验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

React远程动态组件怎么实现

阅读:592 来源:乙速云 作者:代码code

React远程动态组件怎么实现

      远程动态组件实现

      远程动态组件库

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

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

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

      import React from 'react'
      export default ({children}) => {
        return {children}
      }
      import React from 'react'
      export default ({children}) => {
        return {children}
      }

      我们使用 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 (
          
                Loading...
              
          }>       {children}        ) } 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 (
        
          Click Me       Remote Component     
      ) } export default App

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

    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>