React远程动态组件怎么实现

这篇文章主要介绍了React远程动态组件怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇React远程动态组件怎么实现文章都会有所收获,下面我们一起来看看吧。

    远程动态组件实现

    远程动态组件库

    远程动态组件库项目结构如下所示:

    .
    ├── babel.config.js
    ├── package.json
    ├── rollup.config.js
    └── src
        ├── Button.js
        ├── Text.js

    我们简单实现了两个组件 ButtonText

    import React from 'react'
    export default ({children}) => {
      return <button style={{color: 'blue'}}>{children}</button>
    }
    import React from 'react'
    export default ({children}) => {
      return <span style={{color: 'blue'}}>{children}</span>
    }

    我们使用 rollup 对其进行打包,之所以用 rollup 是因为其打包出来的代码非常简洁,方便我们查看,rollup 配置为:

    import babel from 'rollup-plugin-babel'
    import fs from 'fs'
    const components = fs.readdirSync('./src')
    export default components.map((filename) => {
      return {
        input: `./src/${filename}`,
        output: {
          file: `dist/${filename}`,
          format: 'cjs',
        },
        plugins: [babel()],
      }
    })

    打包后的结果如下所示:

    .
    ├── dist
    │   └── Button.js
    │   └── Text.js

    其中 Button.js 如下所示:

    'use strict'
    var React = require('react')
    function _interopDefaultLegacy(e) {
      return e && typeof e === 'object' && 'default' in e ? e : {default: e}
    }
    var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
    var Button = function (_ref) {
      var children = _ref.children
      return /*#__PURE__*/ React__default['default'].createElement(
        'button',
        {
          style: {
            color: 'blue',
          },
        },
        children
      )
    }
    module.exports = Button

    然后我们使用 http-server 在 dist 目录下开启一个静态文件服务,则可以通过 http://localhost:8080/Button.js 获取到打包后的代码。

    远程组件库介绍完毕,接下来介绍业务项目中如何使用。

    接入远程组件库

    我们使用 create-react-app 创建一个 React 应用,并新增一个 DynamicComponent 组件:

    const DynamicComponent = ({name, children, ...props}) => {
      const Component = useMemo(() => {
        return React.lazy(async () => fetchComponent(name))
      }, [name])
      return (
        <Suspense
          fallback={
            <div style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
              <span style={{fontSize: 50}}>Loading...</span>
            </div>
          }>
          <Component {...props}>{children}</Component>
        </Suspense>
      )
    }
    export default React.memo(DynamicComponent)

    这里使用到了 React 中的 Suspense 组件和 React.lazy 方法,关于他们的用法这里不做过多解释,整个 DynamicComponent 组件的含义是远程加载目标组件,这个过程该组件会渲染传入 Suspense 参数 fallback 之中的内容,最后会使用加载成功的组件进行替换。接下来看看 fetchComponent 是如何实现的:

    const fetchComponent = async (name) => {
      const text = await fetch(
        `http://127.0.0.1:8080/${name}.js?ts=${Date.now()}`
      ).then((a) => {
        if (!a.ok) {
          throw new Error('Network response was not ok')
        }
        return a.text()
      })
      const module = getParsedModule(text, name)
      return {default: module.exports}
    }

    该方法会发起网络请求得到组件的代码,并交给 getParsedModule 去解析,最后得到模块返回。我们来看一下 getParsedModule 是怎么实现的:

    const packages = {
      react: React,
    }
    const getParsedModule = (code) => {
      let module = {
        exports: {},
      }
      const require = (name) => {
        return packages[name]
      }
      Function('require, exports, module', code)(require, module.exports, module)
      return module
    }

    这里使用 Function 来运行传入的代码,因为打包远程组件的时候并没有将 react 库打包进去,所以这里需要实现 require 这个方法。

    我们结合之前打包得到的 Button.js 来看这段代码,它其实同下面这个代码是等价的:

    const packages = {
      react: React,
    }
    const getParsedModule = (code, moduleName) => {
      let module = {
        exports: {},
      }
      const require = (name) => {
        return packages[name]
      }
      ;((require, exports, module) => {
        'use strict'
        var React = require('react')
        function _interopDefaultLegacy(e) {
          return e && typeof e === 'object' && 'default' in e ? e : {default: e}
        }
        var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
        var Button = function (_ref) {
          var children = _ref.children
          return /*#__PURE__*/ React__default['default'].createElement(
            'button',
            {
              style: {
                color: 'blue',
              },
            },
            children
          )
        }
        module.exports = Button
      })(require, module.exports, module)
      return module
    }

    最后我们可以按照如下方式来使用 DynamicComponent 组件:

    import DynamicComponent from './DynamicComponent'
    function App() {
      return (
        <div>
          <DynamicComponent name='Button'>Click Me</DynamicComponent>
          <DynamicComponent name='Text'>Remote Component</DynamicComponent>
        </div>
      )
    }
    export default App

    现在我们尝试修改远程动态组件库中的组件,重新打包后就可以马上看到修改后的效果了。

    关于“React远程动态组件怎么实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“React远程动态组件怎么实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注云搜网行业资讯频道。


    【AD】美国洛杉矶/香港/日本VPS推荐,回程电信CN2 GIA线路,延迟低、稳定性高、免费备份_搬瓦工

    【AD】炭云:36元/年/1GB内存/20GB SSD空间/500GB流量/5Gbps端口/KVM/香港/国际线路LUMEN