React18 新特性
自动批量更新 state
- React 18 以前:只有在合成事件中才会合并对 state 的更新,并异步更新。
- React 18:在合成事件、异步任务、原生事件中都会合并对 state 的更新,并异步更新。如果不希望合并的话,React 18 提供了
flushSync
方法以禁用更新。注意不想合并的更新,要写在不同的flushSync
方法中。
并发模式 - Concurrent Mode
主流浏览器刷新频率为 60Hz,即每 1000ms / 60Hz = 16.6ms 浏览器刷新一次。
JS 可以操作 DOM,GUI渲染线程
与 JS线程
是互斥的。所以JS 脚本执行和浏览器布局、绘制不能同时执行。在每 16.6ms 时间内,需要完成JS 脚本执行和浏览器布局、绘制的任务。当JS 脚本执行时间过长,超出了 16.6ms,这次刷新就没有时间执行样式布局和样式绘制了。
在 Concurrent Mode
模式中,React
在每一帧中预留了一定的时间(默认 5ms)给 JS 线程,当预留的时间不够用时,React
将线程控制权交还给浏览器使其有时间渲染 UI,React
则等待下一帧时间到来继续被中断的工作。
useTransition 和 useDeferredValue
useTransition
React
的更新可以分为两类:- 紧急更新:比如点击、输入、拖动等需要立即响应更新的行为,如果不立即更新,会给用户卡顿的感觉。
- 过渡更新:将 UI 从一个视图过渡到另一个视图。有些延迟,不立刻更新是可以接受的。
在开启了并发模式的情况下,默认都是紧急更新。使用了
useTransition
能将紧急更新变为过渡更新。// React 组件中 const [text, setText] = useState(); const [isPending, startTransition] = useTransition(); const handleClick = () => { // 将对 text 的更新,转变为非紧急更新。能让其他的 state 优先更新 startTransition(() => { setText(new Date().toString()); }); }; return ( <> <button onClick={handleClick}>更新</button> {isPending ? <div>loading...</div> : <div>{text}</div>} </> );
useDeferredValue
和useTransition
同理,也是将紧急更新变为过渡更新。区别在于,useTransition
是把更新任务变成了延迟更新任务,而useDeferredValue
是把一个状态变成了延迟的状态。// React 组件中 const [text, setText] = useState(); const handleClick = () => { setText(new Date().toString()); }; return ( <> <button onClick={handleClick}>更新</button> /* 将对 text 的更新,转变为非紧急更新。能让其他的 state 优先更新 */ <div>{useDeferredValue(text)}</div> </> );
严格模式
如果开启了严格模式,在开发模式下,组件的渲染会渲染两次,方便排查一些隐藏的 bug。
SuSpense 组件的变化
// React 17
// 外层的 Suspense 组件 fallback 为 Loading 组件
// 内层的 Suspense 组件 fallback 也为 Loading 组件
<Suspense fallback={<Loading />}>
<Suspense>
<Page />
</Suspense>
</Suspense>
// React 18
// 外层的 Suspense 组件 fallback 为 Loading 组件
// 内层的 Suspense 组件 fallback 为 null
<Suspense fallback={<Loading />}>
<Suspense>
<Page />
</Suspense>
</Suspense>
SuSpense 组件的实现原理:
class SuSpense extends React.Component {
state = { promise: null }
componentDidCatch(e) {
if (e instanceof Promise) {
this.setState({ promise: e }, () => {
e.then(() => {
this.setState({ promise: null }
});
});
}
}
render() {
const { fallback, children } = this.props;
const { promise } = this.state;
return <>{ promise ? fallback : children }</>
}
}
React18 新特性
https://www.reimu747.ink/post/20230131.html