创建时间: 2025-01-21最后更新: 2026-02-23作者: yangbo(8fec8fae98)

0、 use 基础知识

use() 是 React19 提升异步开发体验最重要的 hook. 也是让 useEffect 重要性大幅度削弱的主要原因.

我们可以利用 use 读取 Promise 中的值.

index.ts
1
const value = use(promise)
2
// 读取到的 value 值是 promise 中 resolve 出来的值
NOTE

也可以使用 use 读取 context 中的资源, 后续详细介绍该能力

1、正确理解 promise

这里我们需要特别注意的是, Promise 是指的一个已经创建好的 Promise 对象, 并且, 在该 promise 对象中已经有了确定的 resolve 的结果, use 读取的是 resolve 的值.

注意观察一下下面两种写法

第一种是已经有了结果状态的 Promise 对象

index.ts
1
const _api2 = new Promise((resolve) => {
2
resolve({ value: '_api2' })
3
})
4
5
// good
6
const result = use(_api2)

第二种是函数运行创建 Promise 对象, 此时我们需要注意, 虽然 _api3 执行之后会立即返回一个带有 resolve 结果状态的 Promise, 但是 use 并不能第一时间读取到其值.

index.ts
1
const _api3 = () => {
2
return new Promise(resolve => {
3
resolve({ value: '_api3' })
4
})
5
}
6
7
// bad: get an error
8
const result = use(_api3())

如果我们直接使用第二种, 那么运行之后, React19 会给你如下一个报错.

ATTENTION

async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server.

一个完整的案例代码以及演示效果如下

预览
React introduction
React lets you build user interfaces out of individual pieces called components. Create your own React components like Thumbnail, LikeButton, and Video. Then combine them into entire screens, pages, and apps.
index.tsx
message.tsx
01
import { use } from 'react'
02
import { random } from 'utils/index'
03
import Message from './message'
04
05
const __api = new Promise<{ value: string }>((resolve) => {
06
resolve({ value: random[0] })
07
})
08
09
export default function Demo01() {
10
const result = use(__api)
11
return (
12
<Message message={result.value} />
13
)
14
}

2、在条件判断中使用

NOTE

这是一个反模式, 并不建议在实践中真的这样使用

和其他 hook 一样, use() 必须在函数组件中使用. 但是很不一样的是, use 可以在循环和条件判断语句中使用.

index.ts
1
if (!loading) {
2
result = use(_api2)
3
}

完整的代码与最终的演示效果如下, 你可以在演示案例中多次点击切换按钮查看交互效果.

预览
React introduction
React lets you build user interfaces out of individual pieces called components. Create your own React components like Thumbnail, LikeButton, and Video. Then combine them into entire screens, pages, and apps.
index.tsx
message.tsx
01
import { use, useState } from 'react'
02
import { random } from 'utils/index'
03
import Skeleton from 'components/zmui/skeleton'
04
import Message from './message'
05
06
const __api = new Promise<{ value: string }>((resolve) => {
07
resolve({ value: random[0] })
08
})
09
10
export default function Demo02() {
11
const [loading, setLoading] = useState(false)
12
let result = { value: '' }
13
if (!loading) {
14
result = use(__api)
15
}
16
17
return (
18
<div className='p-4'>
19
{loading ? <Skeleton /> : <Message message={result.value} />}
20
<div className='mt-4 text-right'>
21
<button className='button' onClick={() => setLoading(!loading)}>切换</button>
22
</div>
23
</div>
24
)
25
}
26

3、在异步请求中使用

通常, 我们在处理异步请求时, 也会结合 promise 来使用. 但是我们并不能直接使用 use 来读取异步请求中的 promise, 因为我们已经非常明确, use 只能读取有确定 resolve 结果的 promise 中的值. 但是有可能第一时间异步请求包装的 promise 状态为 pending. 因此在这种情况下, 我们必须结合 Suspense 来使用.

当然, 为了加强对 use 的理解, 我们也准备了一个不顾任何风险提示, 强行等 promise 请求完成之后使用 use 去读取它的值的案例. 代码与演示效果如下.

预览
index.tsx
message.tsx
api.ts
01
import React, { useState, use, useRef } from 'react';
02
import Skeleton from 'components/zmui/skeleton'
03
import Message from './message'
04
import { getMessage } from './api'
05
06
export default function Demo03() {
07
let [loading, setLoading] = useState(true)
08
09
const promise = useRef(getMessage().then(res => {
10
setLoading(false)
11
return res
12
}))
13
14
let result = { value: '' }
15
16
if (!loading) {
17
result = use(promise.current)
18
return <Message message={result.value} />
19
}
20
21
return <Skeleton />
22
}

点击预览工具栏中的刷新按钮可以重新加载执行该组件.

NOTE

最终虽然读取到了 promise 中的值, 但是一定要记住, 这种写法是不安全的, 并不建议在实践中真的这样使用. 而要在实践中采用 Suspense 来处理.

接下来我们要学习 Suspense 的详细知识.

专栏首页
到顶
专栏目录