You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
先来看看官方提供的例子:提交表单更新 name,可以立即将新的 name 更新到 UI 中。请求成功则 UI 不变,请求失败则 UI 回滚。
functionChangeName(){const[name,setName]=useState("");// 定义乐观更新的状态const[optimisticName,setOptimisticName]=useOptimistic(name);constsubmitAction=async(formData)=>{constnewName=formData.get("name");// 请求之前,先把状态更新到 optimisticLikesetOptimisticName(newName);try{awaitupdateName(newName);// 成功之后,更新最终状态setName(newName);}catch(e){console.error(e);}};return(<formaction={submitAction}><p>Your name is: {optimisticName}</p><p><label>Change Name:</label><inputtype="text"name="name"disabled={name!==optimisticName}/></p></form>);}
importReact,{createContext}from'react';constThemeContext=createContext('');functionApp({ children }){return(<ThemeContext.Providervalue="dark">{children}</ThemeContext.Provider>);}
在 React 19 中,我们可以使用 Context来代替 Context.Provider了
functionApp({ children }){return(<ThemeContextvalue="dark">{children}</ThemeContext>);}
未来在某个版本会删除掉 Context.Provider。
ref 支持返回 cleanup 函数
ref 支持返回一个 cleanup 函数,在组件卸载时会调用该函数。
<inputref={(ref)=>{// ref created// NEW: return a cleanup function to reset// the ref when element is removed from DOM.return()=>{// ref cleanup};}}/>
最近 React 发布了 V19 RC 版本,按照惯例,我们对 React 19 的新特性进行一次深度的体验学习,以便尽快上手新特性。
这篇文章,我会通过丰富的示例,演示 React 19 的新特性,以及相较于老版本的差异。同时会附上自己对部分新特性的评价,如有不对,烦请指正。
本文所有示例代码可以在这里查看:https://codesandbox.io/p/sandbox/react19-demo-lmygpv
React 19 的最重要改动,是新增了几个 Hook,均是针对 form 和异步网络请求通用能力的封装。有点类似 react-query 的 useQuery,或者 ahooks 的 useRequest。
在 React Hooks 中,最基本的网络请求我们可能会这样写:
上面是一个最简单的网络请求示例,点击按钮后,请求 updateName 接口,同时维护了 isPending 和 error 两个请求相关的状态。
useTransition 支持异步函数
useTransition 是 React 18 新增的一个 Hook,主要用来标记低优先级更新,低优先级更新是可以被中断的。在 React 18 中,useTransition 返回的 isPending 代表这次低优先级的更新正在等待中。
在 18 中,useTransition 返回的 startTransition 只支持传递同步函数,而在 19 中,增加了对异步函数的支持。通过这个特性,我们可以用来自动维护异步请求的 isPending 状态。代码如下:
上述写法有两个好处:
useActionState 管理异步函数状态
useActionState 是 React 19 新增的一个 Hook,用来管理异步函数,自动维护了 data、action、pending 等状态。
经过 useActionState 改造的代码如下:
上面代码乍一看,感觉很熟悉,好像和大家经常用的 useRequest、useQuery、useSWR 等都差不多。
我们通过 API 来仔细了解一下 useActionState
返回参数含义:
state
:代表 fn 函数返回的内容,fn 未执行时,等于 initialStateformAction
:用来触发 fn 函数执行,可以直接调用,也可以传递给 form 的 action 属性isPending
:fn 函数是否正在执行中传入参数含义:
fn
:一个异步函数,接受两个参数previousState
和formData
previousState
: 代表上一次执行 fn 返回的内容,首次调用等于 initialStateformData
:代表调用 formAction 时传递的参数initialState
:fn 没执行时,默认的 statepermalink
:一个 URL 字符串,通常和服务端组件有关系。(表示暂时没看懂干啥的)你可以能注意到了上面 demo 中使用了 startTransition 来包裹调用 handleSubmit。因为不用 startTransition 来包裹,useActionState 就没用。
官方提供的 demo 是通过 form action 触发的 handleSubmit,其内置了 startTransition ,所以不需要手动设置。
有没有觉得很难用?我是这么觉得的。
useOptimistic 乐观更新
乐观更新是一种常见的体验优化手段,在发送异步请求之前,我们默认请求是成功的,让用户立即看到成功后的状态。
先来看看官方提供的例子:提交表单更新 name,可以立即将新的 name 更新到 UI 中。请求成功则 UI 不变,请求失败则 UI 回滚。
useOptimistic 用来维护临时状态,保证 UI 的乐观更新。
返回参数含义:
optimisticState
:乐观更新的状态,UI 上应该始终消费这个状态。默认等于真正的 state。addOptimistic
:更新 optimisticState,可以通过 updateFn 指定更新逻辑传入参数含义:
state
:真正的状态updateFn
:(currentState, optimisticValue) => newOptimisticState
,调用 addOptimistic 的时候会通过这个函数生成新的 optimisticState这个 Hook API 看起来还是挺简单的。
但是关于上面的 Demo 示例,我有个困惑:如果请求失败了,是怎么让状态回滚呢?
经过测试,上面的代码确实有失败状态回滚的能力。
其奥秘就是异步函数执行结束后,无论是成功还是失败,optimisticName 都会重置成和最新 state 一样。
也就是我们调用了 setName(newName),那 optimisticName 就变成新的状态。如果没调用,则变成之前的状态。
关于乐观更新,我在日常开发中,经常会用到。经典的场景是点赞场景,用户点赞后,立即更新 UI 为点赞成功,如果请求失败后,再回滚 UI。
使用 useOptimistic 后,其代码如下
上面代码看起来很简单,但是没用,会报错
意思是 optimistic state 的更新,必须包裹在 startTransition 里面。
根据告警再优化下代码
增加了 startTransition 后,功能可以正常使用。
为什么官方的示例代码不用加 startTransition 呢?因为官方示例是通过 form 的 action 调用的,其默认内置了 startTransition。
体验下来,我觉得这个 Hook,确实是没啥用,我普通代码实现个乐观更新,更简单。
上面我们介绍了 React 19 新增的几个 Hook,不知道大家看下来什么感受?说说我个人的感受。
React 19 之前的 Hook,基本都是原子级别的,必要的,比如
useState
、useEffect
、useTransition
等,没有它就有些功能实现不了。但 React 19 新增的几个 Hook 明显不是这样的,而是更上层的封装,并且和 form 耦合很严重。
我觉得在实际业务开发中,几乎不会用到上述 Hook。
useFormStatus 获取表单状态
useFormStatus 是 React 19 新增的一个 Hook,主要用来快捷读取到最近的父级 form 表单的数据,其实就是类似 Context 的封装。
useFormStatus 能拿到父级最近的 form 的状态:
pending
:是否正在提交中data
:表单正在提交的数据,如果 form 没有被提交,则为 nullmethod
:form 的 method 属性,get
或post
action
:form 的 action 属性,如果 action 不是函数,则为 nulluseFormStatus 使用场景较窄,绝大部分开发者不会用到。
use
use 是 React 19 新增的一个特性,支持处理 Promise 和 Context。
假如我们要实现这样一个需求:请求接口数据,请求过程中,显示 loading,请求成功,展示数据。
以前我们可能会这样写代码
通过 use 我们可以把代码改造成下面这样
use 接收一个 Promise,会阻塞 render 继续渲染,通常需要配套 Suspense 处理 loading 状态,需要配套 ErrorBoundary 来处理异常状态。
另外 use 也支持接收 Context,类似之前的 useContext,但比 useContext 更灵活,可以在条件语句和循环中使用。
use 的使用有一些注意事项
ref
在之前,父组件传递 ref 给子组件,子组件如果要消费,则必须通过 forwardRef 来消费。
React 19 开始,不需要使用 forwardRef 了,ref 可以作为一个普通的 props 了。
未来在某个版本会删除掉 forwardRef。
Context
在 React 19 之前,我们需要使用
Context.Provider
,比如在 React 19 中,我们可以使用
Context
来代替Context.Provider
了未来在某个版本会删除掉
Context.Provider
。ref 支持返回 cleanup 函数
ref 支持返回一个 cleanup 函数,在组件卸载时会调用该函数。
useDeferredValue 增加了 initialValue 参数
useDeferredValue 现在增加了第二个参数 initialValue,指定初始化值。
支持 Document Metadata
在之前,如果我们希望动态的在组件中指定
meta
、title
、link
等文档属性,我们可能会这样做:在 React 19 中,原生支持了这三个文档属性,支持在组件中设置。
在渲染过程中,React 发现这三种标签,会自动提升到 上。
其它更多特性
precedence
指定样式表的优先级,同样优先级的样式表会被放到一起The text was updated successfully, but these errors were encountered: