【发布时间】:2021-11-14 12:53:21
【问题描述】:
我们正在用 React 组件包装一个组件库,但在某些情况下,该库以这样一种方式操作 DOM 树,使得 React 在尝试删除 React 组件时会崩溃。
这是重现问题的示例:
function Sample ()
{
let [shouldRender, setShouldRender] = React.useState(true);
return (
<React.Fragment>
<button onClick={() => setShouldRender(!shouldRender)}>show/hide</button>
{ shouldRender && <Component /> }
</React.Fragment>
);
}
function Component ()
{
let ref = React.useRef();
React.useEffect(() => {
let divElement = ref.current;
someExternalLibrary.setup(divElement);
return () => someExternalLibrary.cleanup(divElement);
});
return <div ref={ref} id="div1">Hello world</div>;
}
ReactDOM.render(
<Sample />,
document.getElementById('container')
);
let someExternalLibrary = {
setup: function(divElement)
{
let beacon = document.createElement('div');
beacon.id = `beacon${divElement.id}`;
divElement.parentElement.replaceChild(beacon, divElement);
document.body.append(divElement);
},
cleanup: function(divElement)
{
let beacon = document.getElementById(`beacon${divElement.id}`);
beacon.parentElement.replaceChild(divElement, beacon);
}
}
你可以找到this sample on JSFiddle。
上面的示例将呈现与someExternalLibrary 集成的Component。
外部库将元素从 React 组件内部移动到其他地方。
即使外部库使用信标将元素放回其原始位置,当您单击显示/隐藏按钮时,React 仍会在尝试删除组件时报错。
这将是错误
"Error: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
at removeChildFromContainer (https://unpkg.com/react-dom@17/umd/react-dom.development.js:10337:17)
at unmountHostComponents (https://unpkg.com/react-dom@17/umd/react-dom.development.js:21324:11)
at commitDeletion (https://unpkg.com/react-dom@17/umd/react-dom.development.js:21377:7)
at commitMutationEffects (https://unpkg.com/react-dom@17/umd/react-dom.development.js:23437:13)
at HTMLUnknownElement.callCallback (https://unpkg.com/react-dom@17/umd/react-dom.development.js:3942:16)
at Object.invokeGuardedCallbackDev (https://unpkg.com/react-dom@17/umd/react-dom.development.js:3991:18)
at invokeGuardedCallback (https://unpkg.com/react-dom@17/umd/react-dom.development.js:4053:33)
at commitRootImpl (https://unpkg.com/react-dom@17/umd/react-dom.development.js:23151:11)
at unstable_runWithPriority (https://unpkg.com/react@17/umd/react.development.js:2764:14)
at runWithPriority$1 (https://unpkg.com/react-dom@17/umd/react-dom.development.js:11306:12)"
一个简单的解决方法是将现有的 HTML 包装在另一个 DIV 元素中,以便成为组件的根,但不幸的是,这在我们的项目中并不总是可行的,所以我需要另一个解决方案。
解决这个问题的最佳方法是什么?
有没有办法在清理期间使用 ReactFragment 并将 HTMLElement 与片段重新关联?
【问题讨论】:
标签: javascript reactjs