升级到 React 18 和并发模式的常见陷阱

WordPress 6.2 附带React 18 版,这是用于构建块编辑器和所有自定义块的JavaScript库。它具有多项新功能、改进和错误修复,包括一种称为并发模式的新渲染算法。( #45235 )

在并发模式下,React 可以更快地执行UI更新,并保持网页响应。当它处理大型复杂的 UI 更新时,它仍然可以实时处理所有用户输入(鼠标事件、滚动、键盘事件),同时处理它已经在做的工作。

但是,它也引入了一些开发人员需要注意的潜在陷阱,并且可能会破坏一些依赖于事件和状态更新的精确计时的组件。这些陷阱只会影响一小部分复杂且专门的 React 代码。除非您的代码依赖于状态更新的特定时间,否则几乎可以肯定您的代码将继续工作而无需任何更改。

批量状态更新

几乎所有并发模式的陷阱都与称为“批量状态更新”的特性有关。这意味着什么?考虑这个 React 组件:

function ShowX() {
  const [ x, setX ] = useState( 0 );
  console.log( 'rendering with state', x );
  useEffect( () => {
    const handle = setTimeout( () => {
      console.log( 'started setting state' );
      setX( 1 );
      setX( 2 );
      console.log( 'finished setting state' );
    }, 1000 );
    return () => clearTimeout( handle );
  }, [] );
  return <div>{ x }</div>;
}

该组件最初将使用 进行渲染state 0,一秒钟后它将依次进行两次状态更新:先是 to 1,然后是 to 2。在 React 17 中,没有并发模式和自动批处理,控制台中的消息将按以下顺序记录:

rendering with state 0
started setting state
rendering with state 1
rendering with state 2
finished setting state

每个 setX 调用都会立即同步触发一次组件渲染,并且会有两次渲染。当脚本执行 logs 行时finished setting state,两个渲染都已经发生。更新的效果setX(1)也已执行。每隔一段时间就会有一些代码依赖于渲染和/或效果此时已经执行的事实。而正是这种代码是并发模式错误的典型来源。因为在并发模式下,在 React 18 中,记录消息的顺序会有很大的不同:

rendering with state 0
started setting state
finished setting state
rendering with state 2

首先,当finished setting state消息被记录时,还没有渲染发生。那个时候只是预定,还没有执行。

其次,两个setX(1)更新setX(2)都被批处理在一起,并且在批处理两个状态更新之后,只用两个最终值执行了一次渲染。这是错误的另一个来源。如果您的代码依赖于正在执行状态的渲染1,那么它永远不会发生。效果也只与2值一起运行,1效果被跳过。

批量更新和@wordpress/data

批量状态更新的一个特例,通常出现在 WordPress 代码中,是@wordpress/data商店中的调度调用:

const counter = useDispatch( counterStore );
counter.increment();

在这里,分派increment操作最终会导致组件内部的状态更新,该组件从counterStore. 有时,您的代码可以依赖这样一个事实,即在调用之后counter.increment(),所有更新和重新呈现都已同步执行。但是,如上所述,在 React 18 并发模式下,这不会立即发生。更新只是在那个时候安排的。

用于挂载根的新API

如果您的插件或块将其自己的 React UI 安装到页面中,而不是导出 React 组件以由块编辑器呈现,您应该了解用于安装组件根的新 React 18 API。旧的 React 17 方式是render函数 from react-dom或 from @wordpress/element

import { render } from '@wordpress/element';
const el = document.getElementById( 'root' );
render( <App />, el );

这仍然继续有效,您可以继续使用它。唯一的缺点是您会收到有关使用 React 17 遗留 API 的控制台警告,并且在以这种方式安装的 React 应用程序中禁用并发模式。

React 18 的方式是使用新的createRootAPI:

import { createRoot } from '@wordpress/element';
const el = document.getElementById( 'root' );
const root = createRoot( el );
root.render( <App /> );

还有一个额外的步骤:从 DOM 元素创建一个根,然后将 JSX 元素渲染到该根中。以这种方式安装的应用程序将使用新的并发模式。

还有一个用于卸载 React 根目录的新 API。旧的是unmountComponentAtNode( el ),新的是在根对象上调用一个方法:root.unmount()

React 18 中的其他新 API

React 18 中还有其他新的 API 函数,它们也都是由@wordpress/element包导出的:

  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#usedeferredvalue">useDeferredValue</a>
  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#useid">useId</a>
  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#useinsertioneffect">useInsertionEffect</a>
  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#usesyncexternalstore">useSyncExternalStore</a>
  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#usetransition">useTransition</a>
  • <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#starttransition">startTransition</a>

这些都是全新的,不会引入任何向后兼容性问题。如果您想了解或使用它们,请参阅React 18 迁移指南React 文档

订阅评论
提醒
guest的头像

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x