在vue项目中运行react组件

在vue项目中运行react组件

背景介绍

此文的背景源于面试中,被问到,vue和react组件假如需要互通和复用,如何优雅的实现?

  • 除了,开发者手动转代码外。目前,我能想到的就2种解决方案

    1. 方案一:我的另一篇: vue代码和react代码互转(组件库同步):juejin.cn/post/707106…

    2. 方案二:直接让react组件在vue项目中运行,反之也可以。(我的另一篇:juejin.cn/post/708330… )(为了不容易乱,拆成了2篇)

先看实现效果

reactInVue.png

react组件在vue中正常渲染了,并且我还点击了Click me 10多下React的响应render也都正常

具体如何实现?

注意以下demo包含3个文件:(按顺序)

  1. main.js
  2. App.vue
  3. 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
复制代码

实现原理

  1. 引入react 和 react-dom(考虑性能的话,可以按需引入,此处demo没这么做)
  2. 把 react 组件,挂载上去
<div id="reactApp"></div> 等dom元素挂载好

然后,把你的组件,挂载到 <div id="reactApp"></div> 上去
ReactDOM.render( 
    <YourReactComponent />
    document.getElementById('reactApp')
);
复制代码

(其实最初的灵感来源于,我对首屏性能优化里面 嵌套多个根元素 的思路,有兴趣可以点:juejin.cn/post/708079…

重要注意点!

  1. 需要配置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数组的第一位

    为什么呢?

    • 因为我们的关键的 挂载dom的代码,是写在.vue文件内的,我们必须等vue-loader把.vue文件 解析成.js文件我们才能处理.js里面的<Test /> 标签 ReactDOM.render(<Test />, document.getElementById('root'));

    • 不过我们也能不解析<Test /> 标签,比如下面,直接用解析后的结果

      <Test /> 会被解析成: React.createElement(Test, null), 解析jsx.png

总结:

实现 在vue项目中运行react组件,需要关注以下几点:

  1. 不要用vue-cli构建的vue项目来test
  • 因为:cli内置了解析jsx的默认babel-loader配置,会默认把jsx解析成vue的语法,比如: 解析成h(...),而不是react的 React.createElement(...)
  1. 需要配置babel-loader来解析jsx文件
  • 要安装对应的依赖:babel及babel选项
  1. 解析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…


码字不易,点赞鼓励!!

猜你喜欢

转载自juejin.im/post/7083303237616402468