React 18异步方式卸载root

问题描述 投票:0回答:1

我有一个罕见的用例,我需要在我的 React 组件中注册多个根,并在组件卸载时销毁它们。显然,我在渲染时卸载了根。我通过在

root.unmount()
之后立即调用
root.render(...)
来模拟这种情况。在以下示例中:https://codesandbox.io/s/eager-grothendieck-h49eoo?file=%2Fsrc%2FApp.tsx

这会导致以下警告:

Warning: Attempted to synchronously unmount a root while React was already rendering. React cannot finish unmounting the root until the current render has completed, which may lead to a race condition.

此警告对我来说意味着有一种异步方法可以卸载根目录,但我不知道如何操作。将

root.unmount()
包装在异步函数 (
const unmount = async () => root.unmount()
) 中不起作用。有什么想法吗?我在这里完全错了吗?

reactjs react-dom
1个回答
11
投票

在我们的项目中,我们通过

setTimeout
异步卸载。我创建了一个更新的codesandbox,您可以在here找到工作示例。

下面的代码片段显示了如何处理安装和卸载。请注意,安装和卸载通过

setTimeout
与同步渲染循环分离,这是为了避免同步安装和异步卸载之间的竞争。否则,可能会发生组件在从先前的渲染中安装后立即被卸载的情况。

我不相信这是最好的解决方案,但到目前为止它对我们有效。

function MyComponent() {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const rootRef = useRef<ReactDOM.Root>();

  useEffect(() => {
    const renderTimeout = setTimeout(() => {
      if (containerRef.current) {
        console.log("create root");
        rootRef.current =
          rootRef.current ?? ReactDOM.createRoot(containerRef.current);
      }

      if (containerRef.current && rootRef.current) {
        console.log("component render");
        rootRef.current.render(<div>mounted component</div>);
      }
    });

    return () => {
      clearTimeout(renderTimeout);
      console.log("unmount");
      const root = rootRef.current;
      rootRef.current = undefined;

      setTimeout(() => {
        console.log("component unmount");
        root?.unmount();
      });
    };
  }, [rootRef]);

  return <div ref={containerRef}></div>;
}
© www.soinside.com 2019 - 2024. All rights reserved.