我有一个罕见的用例,我需要在我的 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()
) 中不起作用。有什么想法吗?我在这里完全错了吗?
在我们的项目中,我们通过
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>;
}