react发展介绍
yingwinwin
前端开发#
react18note
- react18 Alpha 已经完成
- react18 beta 已经完成
- 进入到RC版本,需要大概1-2个月,具体还需要看反馈 (12月9号左右)
- RC结束之后,需要大概2~4周就会发布react18了。
#
自动批处理如何理解批处理呢?从一道老生常谈的面试题谈起:setState什么时候是同步的,什么时候是异步的?
- 来看一下,下面这段代码 (打开控制台点击按钮查看效果)
效果:
熟悉react的朋友,应该都知道,react会合并处理在事件函数和生命周期的setState的渲染,所以上面在console中的123,会打印1
次。
- 再来看下面这段代码
效果:
结果可能大家也都已经知道了,console里面的值被打印了2
次,也就是说每次点击react组件渲染了2次,在setTimeout中setState的批处理失效了。
那道有名的面试题的答案也就出来了。
- react在事件处理和生命周期函数中是异步处理渲染(合并渲染,也就是批处理)
- 在异步任务中,如:promise.then,setTimeout等异步任务中,会同步进行渲染(不进行批处理)
- 这样看其实setState在18版本之前只能算是半自动批处理。
批处理的概念说完了我们来看一下react18做了什么?
- react18中改掉了这个setState在异步中处理的问题,真正了实现了自动批处理。(狂喜,以后再也不用被setState的面试题支配😎)
如何使用react18的自动批处理呢?需要使用到react提供的新的root Api
tip
- react提供了一个新的root Api,
ReactDOM.createRoot
用于并发渲染,可以选择优先级更高的任务进行渲染。 - 之前我们使用的
ReactDOM.render()
被称为legacy模式
,等待按照顺序渲染。
上面的例子不变,我们来看一下,在react18中的表现。
- 安装包更改为react18@beta版本。
- 需要修改react的挂载模式为createRoot Api形式
- 代码
效果: 可以看到react18即便是在异步操作中,也不会出现重新渲染两次的情况。达到了真正的自动化批处理。
那么问题来了,我们并不是总是需要批处理呀,那怎么实现之前需要异步处理的情况呢?react官方提供了一个api,帮助我们处理这种不需要批处理的情况。
ReactDOM.flushSync
效果:
这样效果的表现和之前放到异步
的表现是一致的。
- 原理就是把setState放到两个不同的优先级中处理,如果setState的话,react会自动合并两个在一个环境中的setState,判定为优先级相同,那么就会一起批量更新。
#
startTransition这个是为了解决,大数据下,渲染顺序的问题。很多时候,同步更新如果js更新内容过大,就会造成用户感受卡顿的感觉。react为了解决这个问题,和fiber开始就已经开始铺路了。这次react18,是全面进行并发的异步模式,让translate变成可能。
以下例子均来源于「React18新特性」深入浅出用户体验大师—transition
通过这个例子可以看出来translate可以最大程度的保护用户体验,在输入内容时,延后list的渲染,不会让用户觉得输入的时候卡顿。
#
为什么不是setTimeout- setTimeout 是异步的执行任务,不会阻碍浏览器的渲染。但是执行的时候,同样会抢浏览器的线程使用,会让用户产生卡顿的感觉。而translate是react使用并发中断当前list渲染,确保input输入,所以不会让用户觉得卡顿。
- setTimeout是异步的,而translate的执行时间会比setTimeout早,是在回调中执行的。可以更好的确保ui的渲染。
#
为什么不是节流防抖- 节流防抖一定程度上可以解决这个问题。但是在节流防抖的时间把控上,需要人为判断,如果时间长可能会给用户造成延迟展示的感觉。早了的话,和
setTimeout
一样还是会有卡顿的感觉。translate
不用考虑这么多。 - 节流防抖本质上还是
setTimeout
,原理是让list渲染的次数减少。translate
是让其延迟展示,而不是减少渲染次数。
#
useTransitionreact 为了更好的使用translate 提供了一个hook函数
- 不用hook使用
- hook使用
图中可以看到,translate的时间可以精准的被判断出来。
#
useDeferredValue图上的效果与useTransition
基本一致。实际上,现在react18工作组,对这两个api也没有一个明确的例子来说明两者明显的区别。在新文档出来之前可能还有一定的修改。具体可以看一下帖子中Dan的回复
- 目前两者区别不大。可能在api使用上有一些区别。
useTransition
可以用于获取等待状态。 - 在执行时机上
useDeferredValue
相比较useTransition
晚一些。
#
useId如果你需要生成一个唯一Id,可以使用useId
#
useSyncExternalStore在引入外部数据的时候,react引入了一个新的api。一般都是由库作者修改。普通开发者用不到,深入了解可以看下面的文章。
- 「React18新特性」深度解读之useMutableSource
- useMutableSource and selector stability #84
- useMutableSource → useSyncExternalStore #86
#
Suspense服务端中引入开箱即用的Suspense
- 请求与suspense一起使用
- Behavioral changes to Suspense in React 18 #7
- React 18 Suspense 的变化
- Update to how we handle null or undefined Suspense fallbacks #72
#
参考文档#
react-router v6#
useNavigatereact-router中会直接依赖history,不需要在
pakeage.json
中额外安装history
依赖,所有导航方法,均从useNavigate()
hook中取得。
#
useRoutes使用
useRoutes
hook,代替react-router-config
,使用js对象定义router,更加简洁。
<Routes/>
#
routes
可以完美替换switch
,但是功能要强过switch
。
<Routes/>
中的路由都是相对的。在<Link to/>
<Route path>
的代码更简洁
- 匹配规则从上到下,改成了最佳匹配路线
下面这种情况,react-router 会选择渲染 NewTteam 组件,因为他的路由更精准,不用怕因为位置写错,而导致的问题了。
- 可以将路由都在一个地方嵌套,而不是分散到各处
<Link to/>
#
Link to 的表现和我们在使用
cd xxx
文件时的表现相似