React 18异步方式卸载root

2024-01-05

我有一个罕见的用例,我需要在我的 React 组件中注册多个根,并在组件卸载时销毁它们。显然,我在渲染时卸载了根。我通过调用模拟了这种情况root.unmount()就在之后root.render(...)。在以下示例中:https://codesandbox.io/s/eager-grothendieck-h49eoo?file=%2Fsrc%2FApp.tsx 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()) 不工作。有任何想法吗?我在这里得到完全错误的东西吗?


在我们的项目中,我们通过以下方式异步卸载setTimeout。我创建了一个更新的codesandbox,你可以找到工作示例here https://codesandbox.io/s/cranky-engelbart-9zl1xf?file=/src/App.tsx.

下面的代码片段显示了如何处理安装和卸载。请注意,安装和卸载通过以下方式与同步渲染循环分离: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>;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React 18异步方式卸载root 的相关文章

随机推荐