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

React中无法绑定自定义Web Component的sendData函数如何解决?

问题:React中无法绑定Web Component的函数参数sendData

使用@r2wc/react-to-web-component创建了自定义Web Component,组件接收sendData函数参数并在点击时执行。React应用中text和color属性正常工作,但sendData函数无法绑定,尝试useLayoutEffect和useEffect监听事件均无效。

Web Component代码

type WCButtonProps = {
  text: string;
  color: string;
  sendData: (text: string) => void;
}

const WCButton: FC<WCButtonProps> = ({
  text,
  color,
  sendData,
}) => {
  return <>
      <button
          style={{ backgroundColor: color ? color : undefined }}
          onClick={() => sendData('Hello')}
      >
          {text}
      </button>
  </>
}

const RWCButton = r2wc(WCButton, {
  shadow: 'open',
  props: {
    text: "string",
    color: "string",
    sendData: "function",
  }
});

customElements.define("rwc-button", RWCButton);

React应用代码

function App() {
  const [text, setText] = useState<string | undefined>('Click me!');
  const [color, setColor] = useState<string | undefined>(undefined);
  const wcButtonRef = useRef<any>(null);

  useLayoutEffect(() => {
    const { current } = wcButtonRef;

    current.addEventListener('sendData', handleClick);

    return () => {
      current.removeEventListener('sendData', handleClick);
    }
  }, [wcButtonRef]);

  const handleClick = (text: string) => {
    alert(text);
  }

  return (
    <div className="App">
      <rwc-button ref={wcButtonRef} text={text} color={color}></rwc-button>
    </div>
  );
}

解决方案

1. 核心原因:Web Component属性不支持直接传递函数

Web Component的标准属性仅支持可序列化的数据类型(字符串、数字等),r2wc虽然允许声明function类型的props,但React在传递函数属性时会将其序列化为字符串,无法传递函数引用,导致绑定失效。

2. 推荐方案:改用自定义事件传递数据

这是符合Web Component标准的做法,通过触发自定义事件替代函数参数:

修改Web Component代码

type WCButtonProps = {
  text: string;
  color: string;
}

const WCButton: FC<WCButtonProps> = ({
  text,
  color,
}) => {
  const handleClick = () => {
    // 触发自定义事件,携带需要传递的数据
    const event = new CustomEvent('sendData', { 
      detail: 'Hello',
      bubbles: true, // 允许事件冒泡到父元素
      composed: true // 允许穿透shadow DOM
    });
    window.dispatchEvent(event);
  };

  return <>
      <button
          style={{ backgroundColor: color ? color : undefined }}
          onClick={handleClick}
      >
          {text}
      </button>
  </>
}

const RWCButton = r2wc(WCButton, {
  shadow: 'open',
  props: {
    text: "string",
    color: "string",
  }
});

customElements.define("rwc-button", RWCButton);

修改React应用代码

function App() {
  const [text, setText] = useState<string | undefined>('Click me!');
  const [color, setColor] = useState<string | undefined>(undefined);
  const wcButtonRef = useRef<any>(null);

  // 用useCallback优化,避免不必要的监听更新
  const handleClick = useCallback((e: CustomEvent) => {
    alert(e.detail); // 获取事件携带的数据
  }, []);

  useEffect(() => {
    const current = wcButtonRef.current;
    if (!current) return;

    current.addEventListener('sendData', handleClick);

    return () => {
      current.removeEventListener('sendData', handleClick);
    }
  }, [handleClick]);

  return (
    <div className="App">
      <rwc-button ref={wcButtonRef} text={text} color={color}></rwc-button>
    </div>
  );
}

3. 备选方案:直接给Web Component实例赋值函数(不推荐)

如果一定要通过props传递函数,可以直接给组件实例赋值,绕过React的属性绑定机制:

function App() {
  // ...其他代码不变

  const handleClick = (text: string) => {
    alert(text);
  }

  useEffect(() => {
    const current = wcButtonRef.current;
    if (!current) return;

    // 直接给实例的sendData属性赋值
    current.sendData = handleClick;

    return () => {
      current.sendData = null;
    }
  }, [handleClick]);

  return (
    <div className="App">
      <rwc-button ref={wcButtonRef} text={text} color={color}></rwc-button>
    </div>
  );
}

这种方式不符合Web Component标准实践,仅作为临时替代方案,可能存在兼容性问题。

内容的提问来源于stack exchange,提问作者Leandro Simonetta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 08:08:20