最近碰到一个问题,系统在海外使用时,进行谷歌翻译后再对表单操作,会导致页面报错:

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>);
};

本人的解决方案是先尝试不允许翻译来解决该问题,但是后面发现,只需要不使用<></>方式就可以解决,故而推测导致这个问题的原因是空标签的特殊场景下的设定导致。


joyerli
158 声望5 粉丝

前端搬砖一枚,会分享一些对技术的个人理解和思考,还会分享一些自己解决实际碰到的业务需而设计的奇葩技术方案。