React 18不再依赖Concurrent Mode开启并发更新了
大家好,我卡颂。
相信很多关注React
进展的朋友都了解Concurrent Mode
,他是「渐进升级」策略的产物。
由于策略调整,根据What happened to concurrent mode?[1],在v18
中将不会有Concurrent Mode
了。
没有Concurrent Mode
,那该如何使用并发更新
呢?
一句话总结:在v18中,不再有三种模式,而是以「是否使用并发特性」作为「是否开启并发更新」的依据。
更详细的解释,让我们一起从React
渐进升级策略的演进过程中寻找答案。
React有多少种架构?
从最老的版本到当前的v18,市面上有多少个版本的React
?
可以从架构角度来概括下,当前一共有两种架构:
- 采用不可中断的「递归」方式更新的
Stack Reconciler
(老架构) - 采用可中断的「遍历」方式更新的
Fiber Reconciler
(新架构)
新架构可以选择是否开启并发更新
,所以当前市面上所有React
版本一定属于如下一种情况:
- 老架构(v15及之前版本)
- 新架构,未开启并发更新,与情况1行为一致(v16、v17默认属于这种情况)
- 新架构,未开启并发更新,但是启用了一些新功能(比如
Automatic Batching
) - 新架构,开启并发更新
理想与现实的差距
React
团队的愿景是:
使用老版本的开发者可以逐步升级到新版,即从情况1、2、3向情况4升级。
但是这中间存在极大的阻力,因为情况4的React
一些行为异于情况1、2、3。
比如如下三个生命周期函数在情况4的React下是“不安全的”:
componentWillMount
componentWillReceiveProps
componentWillUpdate
贸然升级可能造成老代码不兼容。
为了让广大开发者能够平滑过渡,React
团队采用了「渐进升级」方案。
渐进升级第一步
「渐进升级」方案的第一步是规范代码。
v16.3新增了StrictMode
,对开发者编写的「不符合并发更新规范的代码」作出提示,逐步引导开发者写出规范代码。
比如,使用上述「不安全的」生命周期函数时会产生如下报错信息:
StrictMode下使用不安全生命周期函数报错
渐进升级第二步
下一步,React
团队让不同情况的React
可以在同一个页面共存,借此可以让情况4的React
逐步渗入原有的项目。
具体做法是提供三种开发模式:
Legacy
模式,通过ReactDOM.render(<App />, rootNode)
创建的应用遵循该模式。默认关闭StrictMode
,表现同情况2Blocking
模式,通过ReactDOM.createBlockingRoot(rootNode).render(<App />)
创建的应用遵循该模式,作为从Legacy
向Concurrent
过渡的中间模式,默认开启StrictMode
,表现同情况3Concurrent
模式,通过ReactDOM.createRoot(rootNode).render(<App />)
创建的应用遵循该模式,默认开启StrictMode
,表现同情况4
3种模式可用特性对比
为了让不同模式的应用可以在同一个页面内工作,需要调整一些底层实现。
比如:调整之前,大多数事件会统一冒泡到HTML元素
,调整后事件会冒泡到应用所在根元素
。
这些调整工作发生在v17,所以v17也被称作为「开启并发更新」做铺垫的「垫脚石」版本。
最新的渐进升级策略
时间前进到2021年6月8日,v18工作组成立。
在与社区进行大量沟通后,React
团队意识到当前的「渐进升级」策略存在两方面问题。
原因一
首先,由于模式影响的是整个应用,所以无法在同一个应用中完成渐进升级。
举个例子,开发者将应用中ReactDOM.render
改为ReactDOM.createBlockingRoot
,从Legacy
模式切换到Blocking
模式,这会自动开启StrictMode
。
此时,整个应用的「并发不兼容警告」都会上报,开发者还是需要修改整个应用。
从这个角度看,并没有起到「渐进升级」的目的。
原因二
其次,React
团队发现:开发者从新架构中获益,更多是由于使用了并发特性
(Concurrent Feature
)。
并发特性
指开启并发更新
后才能使用的特性,比如:
useDeferredValue
useTransition
所以,可以默认情况下仍使用同步更新
,在使用了并发特性
后再开启并发更新
。
在v18中运行如下代码:
const App = () => {
const [count, updateCount] = useState(0);
const [isPending, startTransition] = useTransition();
const onClick = () => {
// 使用了并发特性useTransition
startTransition(() => {
// 本次更新是并发更新
updateCount((count) => count + 1);
});
};
return <h3 onClick={onClick}>{count}</h3>;
};
由于updateCount
在startTransition
的回调函数中执行(使用了并发特性
),所以updateCount
会触发并发更新
。
如果updateCount
没有作为startTransition
的回调函数执行,那么updateCount
将触发默认的同步更新
。
你可以观察这两种情况是否开启
时间切片
来区分是否是并发更新,完整代码见Demo地址[2]
结论
在v18中,不再有三种模式,而是以「是否使用并发特性」作为「是否开启并发更新」的依据。
具体来说,在v18中统一使用ReactDOM.createRoot
创建应用。
当不使用并发特性
时,表现如情况3。使用并发特性
后,表现如情况4。
React18
稳定版最快明年一月底到来,你还学的动吗?
参考资料
[1]What happened to concurrent mode?: https://github.com/reactwg/react-18/discussions/64
[2]Demo地址: https://codesandbox.io/s/react-concurrent-mode-demo-forked-z7r0j?file=/src/index.js
相关文章
- 跨地域场景下,如何解决分布式系统的一致性?
- 将自由风格项目转换为管道项目 CI/CD
- 手把手教你用Go语言开发一款简易目录生成器
- 断言(assert)有多重要,你不会不知道吧
- 3分钟快速搭建Web服务器,这一篇你值得收藏
- 设计模式系列之建造者模式
- 十大经典排序算法详解之一:冒泡排序,选择排序,插入排序
- TypeScript 中提升幸福感的 10 个高级技巧
- 技术增强: 如何更优雅地开发中间件?
- 开发进阶:Dotnet Core多路径异步终止
- Nacos或者Config是怎么实现配置热刷新的?
- 一篇文章带你了解CSS3 滤镜(Filters)之二
- 引入『客户端缓存』,Redis6算是把缓存玩明白了…
- 最新研究发现超级人工智能,从理论上就无法控制
- GPT“高仿”系列开源了!最大可达GPT-3大小,能自主训练
- 程序员进阶书单:算法篇
- Zookeeper面试常见的11个连环炮
- 简单了解 TiDB 架构
- 浅析经典排序算法之堆排序
- 快来看!简单的代码提交能玩出这么多花样