在vue项目中运行react组件
背景介绍
此文的背景源于面试中,被问到,vue和react组件假如需要互通和复用,如何优雅的实现?
-
除了,开发者手动转代码外。目前,我能想到的就2种解决方案
-
方案一:我的另一篇: vue代码和react代码互转(组件库同步):juejin.cn/post/707106…
-
方案二:直接让react组件在vue项目中运行,反之也可以。(我的另一篇:juejin.cn/post/708330… )(为了不容易乱,拆成了2篇)
-
先看实现效果
react组件在vue中正常渲染了,并且我还点击了Click me 10多下,React的响应render也都正常
具体如何实现?
注意以下demo包含3个文件:(按顺序)
- main.js
- App.vue
- test.jsx
// main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App),
}).$mount('#app')
// App.vue
<template>
<div id="app">
<h1>我是vue组件的内容 {{aa}} </h1>
<h1>我是vue组件的内容 {{aa}} </h1>
<h1>我是vue组件的内容 {{aa}} </h1>
以下将渲染react组件
<hr />
<div id="reactApp"></div>
</div>
</template>
<script>
import React from 'react'; // 此处用的是 18 版本
import * as ReactDOM from 'react-dom/client'; // 此处用的是 18 版本(写法有点改变)
import Test from "./test.jsx"
export default {
data () {
return {
aa: 1111
}
},
mounted () {
const container = document.getElementById('reactApp');
const root = ReactDOM.createRoot(container);
// root.render(<Test />); // 下面有解释,解析jsx的babel-loader要放在rules数组的第一位,此行才能替代下面一行。
root.render(React.createElement(Test, null));
// 此处这个写法是 react-dom的18版本的写法 : "react": "^18.0.0", "react-dom": "^18.0.0"
// 18版本以内的话,直接下面这样写就可以了
// ReactDOM.render(
// React.createElement(Test, null),
// document.getElementById('reactApp')
// );
}
}
</script>
// test.jsx
import React, { useState } from 'react';
function Test() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Test
复制代码
实现原理
- 引入react 和 react-dom(考虑性能的话,可以按需引入,此处demo没这么做)
- 把 react 组件,挂载上去
<div id="reactApp"></div> 等dom元素挂载好
然后,把你的组件,挂载到 <div id="reactApp"></div> 上去
ReactDOM.render(
<YourReactComponent />
document.getElementById('reactApp')
);
复制代码
(其实最初的灵感来源于,我对首屏性能优化里面 嵌套多个根元素 的思路,有兴趣可以点:juejin.cn/post/708079… )
重要注意点!
- 需要配置babel,来解析jsx
-
(此处千万不要用vue-cli构建的项目来test,我当前使用的vue-cli版本构建的项目,他内置了babel来解析jsx,会解析成vue语法)
webpack.config.js
// webpack.config.js module.exports = { // ... module: { rules: [ { test: /.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options:{ "presets": ["@babel/preset-react", "@babel/preset-env"], "plugins": ["@babel/plugin-transform-runtime"] } } } ] } } // 另外我把我的babel的版本贴一贴,babel需要安装几个依赖,才能解析react的jsx语法 /* "@babel/core": "^7.12.9", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.13.9", "@babel/preset-react": "^7.16.7", "babel-loader": "^8.2.2", */ 复制代码
此处有个重要细节,和webpack的loader执行顺序相关的:解析jsx的babel-loader最好放在rules数组的第一位
扫描二维码关注公众号,回复: 13770808 查看本文章为什么呢?
-
因为我们的关键的 挂载dom的代码,是写在.vue文件内的,我们必须等vue-loader把.vue文件 解析成.js文件,
我们才能处理.js里面的<Test /> 标签 ReactDOM.render(<Test />, document.getElementById('root'));
-
不过我们也能不解析
<Test /> 标签
,比如下面,直接用解析后的结果<Test /> 会被解析成: React.createElement(Test, null),
-
总结:
实现 在vue项目中运行react组件,需要关注以下几点:
- 不要用vue-cli构建的vue项目来test
- 因为:cli内置了解析jsx的默认babel-loader配置,会默认把jsx解析成vue的语法,比如: 解析成h(...),而不是react的 React.createElement(...)
- 需要配置babel-loader来解析jsx文件
- 要安装对应的依赖:babel及babel选项
- 解析jsx的babel-loader最好放在rules数组的第一位
- 因为我们的react的关键的 挂载dom的代码,是写在.vue文件内的,所以我们必须等vue-loader把.vue文件 解析成.js文件,我们才能处理.js里面的
<Test /> 标签 , 比如 ReactDOM.render(<Test />, document.getElementById('root'));
另外,此处只是以小demo的形式,来更好的理解 在vue项目中运行react组件 的原理。实际开发的话,react组件也会有其他依赖,这些依赖要一并的引入,才能正常运行组件
最终在对比一下,vue项目中使用react组件,和, react项目中使用vue组件,配置上的区别!
一定需要配置webpack.config.js的loader吗? | |
---|---|
在vue项目中使用react组件 | yes,需配置babel-loader,编译.jsx文件,需要额外注意配babel-loader的option选项 |
在react项目中使用vue组件 | no,如果不用解析.vue文件的话,直接用vue的组件选项对象语法的话,那么不用额外的配置vue-loader。需要支持.vue文件的话,需要配vue-loader |
另一篇的快速链接:juejin.cn/post/708330…
码字不易,点赞鼓励!!