use
用来直接读取Promise或Context的值,通常和Suspense一起使用
use() 可以读取 Promise 或 Context,如果 Promise 还没有完成,React 会暂停渲染,并交给 Suspense 显示 fallback。
用法
异步数据加载
实现卡片效果,在数据加载过程中展示骨架屏,数据加载完后显示卡片详情
TIP
建议升级到React19,因为用到了use这个API,在之前版本这个时实验性特性,在19版本才纳入正式特性
模拟数据,我们可以放到public目录下
http://localhost:5173/data.json
Card组件
json
{
"data": {
"id": 1,
"address": "北京市房山区住岗子村10086",
"name": "小满",
"age": 26,
"avatar": "https://api.dicebear.com/7.x/avataaars/svg?seed=小满"
}
}tsx
import { use } from 'react'
import './index.css'
interface Data {
name: string
age: number
address: string
avatar: string
}
const getData = async () => {
await new Promise((resolve) => setTimeout(resolve, 2000))
return (await fetch('http://localhost:5173/data.json').then((res) =>
res.json()
)) as { data: Data }
}
const dataPromise = getData()
const Card: React.FC = () => {
const { data } = use(dataPromise)
return (
<div className="card">
<header className="card-header">
<div className="card-name">{data.name}</div>
<div className="card-age">{data.age}</div>
</header>
<section className="card-content">
<div className="card-address">{data.address}</div>
<div className="card-avatar">
<img width={50} height={50} src={data.avatar} alt="" />
</div>
</section>
</div>
)
}
export default Cardcss
.card {
width: 300px;
height: 150px;
border: 1px solid #d6d3d3;
margin: 30px;
border-radius: 2px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #d6d3d3;
padding: 10px;
}
.card-age {
font-size: 12px;
color: #999;
}
.card-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
}骨架屏组件
tsx
import './index.css'
export const Skeleton = () => {
return (
<div className="skeleton">
<header className="skeleton-header">
<div className="skeleton-name"></div>
<div className="skeleton-age"></div>
</header>
<section className="skeleton-content">
<div className="skeleton-address"></div>
<div className="skeleton-avatar"></div>
</section>
</div>
)
}css
.skeleton {
width: 300px;
height: 150px;
border: 1px solid #d6d3d3;
margin: 30px;
border-radius: 2px;
}
.skeleton-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #d6d3d3;
padding: 10px;
}
.skeleton-name {
width: 100px;
height: 20px;
background-color: #d6d3d3;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
.skeleton-age {
width: 50px;
height: 20px;
background-color: #d6d3d3;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
.skeleton-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
}
.skeleton-address {
width: 100px;
height: 20px;
background-color: #d6d3d3;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
.skeleton-avatar {
width: 50px;
height: 50px;
background-color: #d6d3d3;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
@keyframes skeleton-loading {
0% {
opacity: 0.6;
}
50% {
opacity: 1;
}
100% {
opacity: 0.6;
}
}tsx
import React, { Suspense } from 'react'
import Card from './components/Card'
import { Skeleton } from './components/Skeleton'
const App: React.FC = () => {
return (
<>
<Suspense fallback={<Skeleton />}>
<Card />
</Suspense>
</>
)
}
export default App与useEffect的区别
useEffect时组件已经渲染了,再去请求
而use是,发现了Promise,等待完成后,再接着渲染