Skip to content

use ​

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

我们可以利用 use 读取 Promise 中的值。也可以使用 use 读取 context 中的资源

正确理解 promise ​

tsx
const value = use(promise);

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

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

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

tsx
const _api2 = new Promise((resolve) => {
  resolve({ value: '_api2' });
});

// good
const result = use(_api2);

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

tsx
function _api3() {
  return new Promise((resolve) => {
    resolve({ value: '_api3' });
  });
}

// bad: get an error
const result = use(_api3());

如果我们按照以往的习惯,直接使用第二种,那么运行之后,React19 会给你如下一个报错。

::: error

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.

:::

在条件判断中使用 ​

和其他 hook 一样,use() 必须在函数组件中使用。

但是很不一样的是,use 可以在循环和条件判断语句中使用。我们这里如下案例来演示这个结论。

在这个例子中,use 被使用在 if(!loading) 条件判断中来获取 result 的值。

tsx
import { use, useState } from 'react';
import Message from './Message';
import Button from './Button';
import Skeleton from './Skeleton';

const _api2 = new Promise((resolve) => {
  resolve({ value: 'Unlike React Hooks, use can be called within loops and conditional statements like if. Like React Hooks, the function that calls use must be a Component or Hook.' });
});

export default function Demo01() {
  const [loading, setLoading] = useState(false);
  let result = { value: '' };
  if (!loading) {
    result = use(_api2);
  }

  return (
    <>
      {loading ? <Skeleton /> : <Message message={result.value} />}
      <div className="mt-4 text-right">
        <Button signal onClick={() => setLoading(!loading)}>切换</Button>
      </div>
    </>
  );
}

在异步请求中使用 ​

通常,我们在处理异步请求时,也会结合 promise 来使用。

但是我们并不能直接使用 use 来读取异步请求中的 promise,因为我们已经非常明确,use 只能读取有确定 resolve 结果的 promise 中的值。

但是有可能第一时间异步请求包装的 promise 状态为 pending。

因此在这种情况下,我们必须结合 Suspense 来使用。

在实践中,如果我们要读取异步请求的 promise 中的值,必须结合 Suspense 来处理 否则,虽然我们最终读取到了 promise 中的值,内容也顺利渲染出来了,但是中间存在一次明显的闪烁,这种体验非常的糟糕。

在低版本中使用 ​

早在 React 16 的后期版本中,就提供了对 Suspense 的支持,

因此,我们只需要在这个基础之上,自己定义一个 use 方法,去读取 promise 中的值就可以实现use + Suspense 结合的效果了。

自定义的代码如下

js
export default function use(promise) {
  if (promise.status === 'fulfilled') {
    return promise.value;
  }
  else if (promise.status === 'rejected') {
    throw promise.reason;
  }
  else if (promise.status === 'pending') {
    throw promise;
  }
  else {
    promise.status = 'pending';
    promise.then((result) => {
      promise.status = 'fulfilled';
      promise.value = result;
    }, (reason) => {
      promise.status = 'rejected';
      promise.reason = reason;
    });
    throw promise;
  }
}

Contributors ​

作者:Long Mo
字数统计:805 字
阅读时长:3 分钟
Long Mo
文章作者:Long Mo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Longmo Docs !