React 19 终于正式发布了: https://react.dev/blog/2024/12/05/react-19
新版本中新增了许多功能, 其中, 一些功能是我们重点关注的:
useActionState
use
useOptimistic
ref
作为 props 传递在使用 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 仍然不是一定足够可靠的功能. 之前 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>
</>
);
}
在上面的例子中, 我们区分了 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>
</>
);
}
在大多数情况下, 这是一个纯优化, 并不会功能有影响.
这种优化甚至还有负面效果, 比如:
之前, ref 作为 props 传递的时候时会报错. 需要使用 forwardRef 来传递. 但是, 现在 React 19 中, 不再需要使用 forwardRef 来传递, 可以直接传递 ref.
官方演示为:
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
//...
<MyInput ref={ref} />