能否在Vue.js中使用React.js组件及包、反之是否也可实现?
无需Vuera在Vue项目中复用React组件的实现方法
目前有两种成熟的无第三方跨框架库的实现方案,适配新版React、Vue3/Vue2都可以正常使用:
方案1:手动编写Vue包装组件(最灵活,无额外依赖)
核心逻辑是在Vue组件的生命周期中调用ReactDOM的能力挂载、卸载React组件,同时处理双向数据同步和事件透传,操作步骤如下:
- 首先在Vue项目中安装React运行时依赖:
# 核心依赖 npm install react react-dom # TS项目额外安装类型定义 npm install @types/react @types/react-dom -D - 编写Vue包装组件,示例如下(以Vue3+React18为例):
<template> <!-- React组件的挂载容器 --> <div ref="reactContainer"></div> </template> <script setup> import { ref, onMounted, onUnmounted, watch } from 'vue' import React from 'react' import { createRoot } from 'react-dom/client' // 导入你要复用的旧React组件 import OldReactButton from './components/OldReactButton.jsx' const reactContainer = ref(null) let reactRoot = null // 组件挂载时初始化React实例 onMounted(() => { reactRoot = createRoot(reactContainer.value) renderReactComp() }) // 渲染React组件,同步Vue侧的props和事件 const renderReactComp = () => { reactRoot.render( <OldReactButton // 透传Vue侧传入的属性 btnText="提交" type="primary" // 把React组件触发的事件转为Vue自定义事件向外透传 onBtnClick={handleReactEvent} /> ) } const handleReactEvent = (eventParams) => { // 此处可以处理React事件返回的参数,按需传递给Vue侧逻辑 console.log('React组件触发事件', eventParams) } // 如果需要支持响应式属性同步,监听对应props变化,重新调用renderReactComp即可,React的diff算法会自动处理更新,不会有性能问题 // Vue组件卸载时销毁React实例,避免内存泄漏 onUnmounted(() => { reactRoot.unmount() }) </script>
如果是Vue2项目,只需要把生命周期钩子对应改为mounted、beforeDestroy,React渲染方法替换为对应版本的ReactDOM.render即可。
方案2:基于Web Components做通用中间层
如果有大量React组件需要复用,或者后续还要适配其他框架,可以把React组件编译为标准Web Components(自定义元素),Vue对原生自定义元素有原生支持,不需要额外适配:
- 先把React组件封装为自定义元素,示例代码如下:
// react-button-wc.jsx import React from 'react' import { createRoot } from 'react-dom/client' import OldReactButton from './OldReactButton.jsx' class ReactButton extends HTMLElement { connectedCallback() { this.root = createRoot(this) this.render() } // 声明需要监听的属性,属性变化时自动触发更新 static get observedAttributes() { return ['btn-text', 'disabled'] } attributeChangedCallback() { this.render() } render() { const btnText = this.getAttribute('btn-text') const disabled = this.hasAttribute('disabled') this.root.render( <OldReactButton btnText={btnText} disabled={disabled} onBtnClick={(e) => { // 抛出原生自定义事件,Vue侧可以直接监听 this.dispatchEvent(new CustomEvent('btn-click', { detail: e })) }} /> ) } disconnectedCallback() { this.root.unmount() } } // 注册自定义元素 customElements.define('react-button', ReactButton) - 在Vue项目中引入上述文件后,直接像原生HTML标签一样使用即可:
<template> <react-button btn-text="提交" @btn-click="handleClick" /> </template>
注意事项
- 如果React组件依赖React生态的上下文(比如Redux、React Query等),需要在包装层加上对应的Provider组件,保证上下文正常传递
- 跨框架通信尽量传递基础类型参数,避免直接传递复杂响应式对象,减少两边响应式系统的冲突
- 如果是SSR项目,需要给跨框架的包装组件加上客户端渲染标记,避免服务端渲染报错
内容的提问来源于stack exchange,提问作者Yash Sonalia
相关产品推荐
相关产品推荐

