前言
2022 年 3 月 29 日,React 团队宣布 React 18 正式发布。其中更新了的功能并不多,但可以说相较之前又跨了一大步,我在网上看到一个评价,说从此以后 react 不再是一个 framework 或者 lib 了,而是 react os,那究竟是不是有那么神奇,咱们可以来简单看看。
新特性
Automatic Batching
感觉这会是一个将来的热门面试考点,我们知道 react 是有批量更新的机制的,即使你多次 setState,react 触发批量更新后,也会把计算合并,只执行最后一次 setState,主要是因为 react 本身有一个字段 isBranchUpdate 标识了是否在批量更新中。
所以在 react 18 版本之前会有这么一个问题
componentDidMount() {
setTimeout(() => {
this.setState({
index: this.state.index + 1
})
console.log('state', this.state.index);
this.setState({
index: this.state.index + 1
})
console.log('state', this.state.index);
}, 0);
}
该段代码执行的结果是
我相信很多 react 八股文都有说过这个,这是因为 setState 并不是异步的,而是根据 isBranchUpdate 的字段决定是否批量更新,而批量更新才是造成我们认为这是异步的关键,当 isBranchUpdate 为 false 时,不再批量更新状态中,setState 就可以立即生效。
在 react 18 以后,批量更新会自动开启,那么以上那段代码如果在 react 18 以后版本结果就会是
Concurrent Mode
Concurrent Mode 即并发模式,与之对应的是 Legacy Mode。
我认为这次的更新,最主要的是 react 多了一个并发模式,什么是并发模式呢,这就得从 react 的一些理念以及之前版本讲起了。
react 的理念里最主要的是用户体验,之前有一次重量级更新,react 的 reconciler 从 stack reconciler 更新到 fiber reconciler,就是基于优化用户体验为目的来做的,大致就是 stack reconciler 在执行的时候,是无法中断的,假如这段逻辑的执行时间超过 16.7 ms,那么屏幕就会卡顿,用户体验不好。 更新到 fiber reconciler 后,reconciler 是可以中断的。 当 reconciler 时间执行过长时,就会中断,把线程控制器交还给浏览器渲染 ui ,ui 渲染完到 react 时,再从中断处开始重新执行,这样屏幕就不会卡顿,而这么个中断重启的异步操作就是 fiber 架构所带来的优化。
reconciler 工作的阶段被称为 render 阶段,用来计算组件的信息,目前已经实现了异步可中断执行了,render 阶段之后是 commit 阶段,即把 render 阶段计算出来的信息渲染在页面上,在 18 版本之前,该阶段不可中断,在 18 版本以后,开启并发模式,渲染在页面上的操作就是异步可中断的了(之前应该是自己理解错误)开启并发模式后,让页面的渲染变得有优先级,但是 commit 阶段应该是不可中断的。
但是并发模式是需要开启的,react 官网就有相应代码,把之前的 render
import { render } from 'react-dom';
const container = document.getElementById('app');
render(<App tab="home" />, container);
替换成 createRoot
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App tab="home" />);
Transitions
上面刚说并发模式带来了渲染可以异步可中断的效果,那么 transitions 带来的是调度效果,其实在 fiber 架构里就已经有了 scheduler,但那是服务于 render 阶段的 reconciler,transitions 就是服务于 commit 阶段的 renderer。
什么叫调度效果,就是相当于给不同 state 的更新赋予不同的优先级,主要就是两种,一种是正常的(或者说是高的也行)优先级,一种是低优先级。
与这个特性相关的有三个 api,startTransition、useTransition 和 useDeferredValue,这里大致介绍一下 startTransition 的用法
componentDidMount() {
setImportantState(1)
startTransition(() => {
setUnimportantState(1)
});
}
即把可能会影响页面渲染的、不重要的更新放在 startTransition 里即可。
而且与 suspence 的搭配,可以很好的解决页面 loading 的渲染,达到更好的用户体验。
总结
其实 react 18 更新的点还有不少,但是标题都说了浅谈嘛,那就只是简单聊聊我自己对这次更新的认知。我觉得 react 在用户体验方面确实做的非常的好,并且还在持续的优化,这次的并发模式以及 transitions,很好的解决了以前我们经常要使用防抖节流等等第三方库的一些成熟方法才能解决的问题(输入框搜索并请求这类的),并且这次的更新,对之前的旧代码也很好兼容,即使你切换成并发模式,成本也并不大,当然目前我还是没有在项目中升级,但如果有新项目我应该会尝试使用,好的,拜拜~