仓库源文站点原文

React 19 终于正式发布了: https://react.dev/blog/2024/12/05/react-19

新版本中新增了许多功能, 其中, 一些功能是我们重点关注的:

  1. useActionState
  2. use
  3. useOptimistic
  4. ref 作为 props 传递

useActionState

在使用 useActionState 的时候, 我们需要注意的是, 在函数内部能否调用 setState 函数对数据进行部分修改.

官方演示非常清晰, 这里稍作修改:

function DataTable({ name }) {
  const [result, updateData, isPending] = useActionState(
    async (previousState, name) => {
      const result = await getDataPromise(name);
      return result;
    },
    new Result(),
  );

  return (
    <>
      <Table data={result} isPending={isPending} />
      <button
        type="submit"
        disabled={isPending}
        onClick={() => {
          updateData(name);
        }}
      >
        Update
      </button>
    </>
  );
}

use

use 仍然不是一定足够可靠的功能. 之前 React 团队就说了 use 的局限性, 现在 React 19 仍然没有解决这个问题.

我们预期仅在初始化数据的时候使用 use, 在更新数据的时候仍使用 useState. 在组件中, 同时保有这两种状态管理的方式, 比如:

function MyComponent() {
  const initData = use(getDataPromise());
  // 👆 因为现在不能在渲染组件中创建 Promise, 所以现在会报错
  const [data, setData] = useState<Data | null>(null);
  const currentData = useMemo(() => data ?? initData, [data, initData]);

  return (
    <>
      {currentData}
      <button
        onClick={async () => {
          const data = await getDataPromise();
          setData(data);
        }}
      >
        Set Data
      </button>
    </>
  );
}

不过, 如何我们区分初始化数据和更新数据, 仅在系统初始化数据的时候使用 use, 那么 use 仍然是一个非常有用的功能. 比如:

const configPromise = getConfigPromise();

function MyComponent() {
  const config = use(configPromise);
  const [data, setData] = useState<Data | null>(null);

  return (
    <>
      {data}
      <button
        onClick={async () => {
          const data = await getDataPromise(config);
          setData(data);
        }}
      >
        Set Data
      </button>
    </>
  );
}

useOptimistic

在上面的例子中, 我们区分了 initData, data 和 currentData. 在 React 19 中, 我们使用 useOptimistic 可以对前端预计修改成功的数据进行优化. 比如:

function MyComponent() {
  const [data, setData] = useState<Data | null>(null);
  const [currentData, setOptimisticData] = useOptimistic(data);

  return (
    <>
      {currentData}
      <button
        onClick={async () => {
          setOptimisticData(tempData);
          const data = await getDataPromise(tempData);
          setData(data);
        }}
      >
        Set Data
      </button>
    </>
  );
}

在大多数情况下, 这是一个纯优化, 并不会功能有影响.

这种优化甚至还有负面效果, 比如:

  1. 如果用户在点击按钮之后, 已经渲染了新的数据, 这时用户认为已经完成.
  2. 然后, 如果后端数据更新失败, 那么数据会重置回错误之前的数据, 但用户不一定会注意到.

ref 作为 props 传递

之前, ref 作为 props 传递的时候时会报错. 需要使用 forwardRef 来传递. 但是, 现在 React 19 中, 不再需要使用 forwardRef 来传递, 可以直接传递 ref.

官方演示为:

function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />