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

  1. 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>}
        </>
    );
  2. 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
作者
Reimu747
发布于
2023年1月31日
许可协议