You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目集成Web组件切换路由时报错:__reactFiber$xxx不可删除

问题描述

现有两个部署在独立服务器的Web组件,单独访问均能正常显示:

服务器A

VIEW: abc.com/a/index.html

CONFIGURATION
abc.com/a/a.js
abc.com/a/main.css
<a-webcomponent>

服务器B

VIEW: abc.com/b/index.html

CONFIGURATION
abc.com/b/b.js
abc.com/b/main.css
<b-webcomponent>

将两者集成到新React项目中,在index.html中配置了两者的资源:

<!DOCTYPE html>
<html lang="en">
<head>
   
    <script src="abc.com/a/a.js"></script>
    <link href="abc.com/a/main.css" rel="stylesheet"/>

    <script src="abc.com/b/b.js"></script>
    <link href="abc.com/b/main.css" rel="stylesheet"/>

</head>
<body>
    <div id="root"></div>
</body>
</html>

路由配置如下:

<Route path="/a-webcomponent" Component={AWebComponent} />
<Route path="/b-webcomponent" Component={BWebComponent} />

对应组件代码:

  • AWebComponent:
return <a-webcomponent />
  • BWebComponent:
return <b-webcomponent />

切换路由时出现报错:

Uncaught TypeError: property "__reactFiber$wqjvbwadizh" is non-configurable and can't be deleted
(中文翻译:未捕获的类型错误:属性"__reactFiber$wqjvbwadizh"不可配置,无法删除)

解决方案

这个错误是React处理Web Component时的常见冲突:React会给DOM元素添加内部标识属性(如__reactFiber$xxx),而部分Web Component的销毁/重建逻辑可能会尝试修改或删除这些不可配置的属性,触发报错。以下是几种可行的解决办法:

1. 动态按需加载Web Component资源

不在index.html中一次性加载两个组件的资源,而是在对应路由组件挂载时再动态加载,切换路由时清理资源,避免全局环境冲突:

修改AWebComponent示例:

import { useEffect, useRef } from 'react';

function AWebComponent() {
  const containerRef = useRef(null);

  useEffect(() => {
    // 检查a.js是否已加载,未加载则动态创建标签引入
    if (!document.querySelector('script[src="abc.com/a/a.js"]')) {
      const script = document.createElement('script');
      script.src = 'abc.com/a/a.js';
      document.head.appendChild(script);
    }
    // 同理加载CSS
    if (!document.querySelector('link[href="abc.com/a/main.css"]')) {
      const link = document.createElement('link');
      link.href = 'abc.com/a/main.css';
      link.rel = 'stylesheet';
      document.head.appendChild(link);
    }

    // 组件卸载时清理资源
    return () => {
      const script = document.querySelector('script[src="abc.com/a/a.js"]');
      if (script) document.head.removeChild(script);
      const link = document.querySelector('link[href="abc.com/a/main.css"]');
      if (link) document.head.removeChild(link);
      // 清理自定义元素定义(浏览器支持的话)
      if ('customElements' in window && customElements.get('a-webcomponent')) {
        customElements.define('a-webcomponent', class extends HTMLElement {});
        customElements.delete('a-webcomponent');
      }
    };
  }, []);

  return <div ref={containerRef}><a-webcomponent /></div>;
}

export default AWebComponent;

BWebComponent做同样的修改,确保两个组件的资源仅在对应路由激活时存在于页面中。

2. 使用React Portal隔离Web Component

将Web Component挂载到独立的DOM节点上,避免React内部属性被Web Component的逻辑干扰:

import { useEffect, useRef, createPortal } from 'react';

function AWebComponent() {
  const portalRoot = useRef(null);

  useEffect(() => {
    // 创建独立的DOM节点作为Portal容器
    const div = document.createElement('div');
    document.body.appendChild(div);
    portalRoot.current = div;

    // 动态加载资源(同方法1的加载逻辑)
    if (!document.querySelector('script[src="abc.com/a/a.js"]')) {
      const script = document.createElement('script');
      script.src = 'abc.com/a/a.js';
      document.head.appendChild(script);
    }
    if (!document.querySelector('link[href="abc.com/a/main.css"]')) {
      const link = document.createElement('link');
      link.href = 'abc.com/a/main.css';
      link.rel = 'stylesheet';
      document.head.appendChild(link);
    }

    // 卸载时清理容器和资源
    return () => {
      if (portalRoot.current) {
        document.body.removeChild(portalRoot.current);
      }
      const script = document.querySelector('script[src="abc.com/a/a.js"]');
      if (script) document.head.removeChild(script);
      const link = document.querySelector('link[href="abc.com/a/main.css"]');
      if (link) document.head.removeChild(link);
    };
  }, []);

  return portalRoot.current ? createPortal(<a-webcomponent />, portalRoot.current) : null;
}

3. 调整Web Component的销毁逻辑(若有权限修改源码)

如果能拿到两个Web Component的源码,检查是否存在遍历DOM元素属性并全部删除的逻辑(比如Object.keys(element).forEach(key => delete element[key])),改成仅删除组件自身添加的属性,不要触碰React的内部标识属性。


内容的提问来源于stack exchange,提问作者Honey Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:55:40