最近碰到一个问题,系统在海外使用时,进行谷歌翻译后再对表单操作,会导致页面报错:
Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
at removeChild (react-dom.development.js:7601:1)
at unmountHostComponents (react-dom.development.js:20449:1)
at commitDeletion (react-dom.development.js:20500:1)
at commitMutationEffects (react-dom.development.js:22782:1)
去掉相关业务代码后,发现可以这样复现:
const Text: React.FC<{ text?: string }> = ({ text = '-' }) => {
return (<>{text}</>);
};
const Demo: React.FC<any> = () => {
const [text, setText] = React.useState<string>('初始值');
return (<div>
<p><Text text={text} /></p>
<button type='button' onClick={() => {
setText('改变后' + Math.random());
}}>改变</button>
</div>);
};
在不经过谷歌翻译时,点击「改变」按钮逻辑一切正常执行。当渲染完毕,先使用谷歌翻译进行翻译后在点击改变按钮,会发现组件的re-render失效。但此demo中不会有报错,报错的原因应该是复杂的使用环境导致。
继续研究发现,该写法下,如果不经过谷歌范围,生成的dom结构为:
<div><p>-</p><button type="button">改变</button></div>
经过谷歌翻译后,dom结构会被谷歌翻译改为:
<div>
<p>
<font style="vertical-align: inherit;">
<font style="vertical-align: inherit;">初始值</font>
</font>
</p>
<button type="button">
<font style="vertical-align: inherit;">
<font style="vertical-align: inherit;">Change</font>
</font>
</button>
</div>
猜测:空标签(<></>
,<React.Fragment></React.Fragment>
)生成的dom结构如果受到了非react控制的dom结构变化会导致空标签内容re-render失效。
所以问题的解决方案为,在Text组件中,添加元素包裹:
const Text: React.FC<{ text?: string }> = ({ text }) => {
return (<span>{text}</span>);
};
如果该解决方法无法解决问题,可以添加禁止元素内内容翻译:
const Text: React.FC<{ text?: string }> = ({ text }) => {
return (<span class="notranslate">{text}</span>);
};
本人的解决方案是先尝试不允许翻译来解决该问题,但是后面发现,只需要不使用<></>
方式就可以解决,故而推测导致这个问题的原因是空标签的特殊场景下的设定导致。