React远程动态组件怎么实现

其他教程   发布日期:2024年04月24日   浏览次数:394

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

    远程动态组件实现

    远程动态组件库

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

    1. .
    2. ├── babel.config.js
    3. ├── package.json
    4. ├── rollup.config.js
    5. └── src
    6. ├── Button.js
    7. ├── Text.js

    我们简单实现了两个组件

    1. Button
    1. Text
    1. import React from 'react'
    2. export default ({children}) => {
    3. return <button style={{color: 'blue'}}>{children}</button>
    4. }
    1. import React from 'react'
    2. export default ({children}) => {
    3. return <span style={{color: 'blue'}}>{children}</span>
    4. }

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

    1. import babel from 'rollup-plugin-babel'
    2. import fs from 'fs'
    3. const components = fs.readdirSync('./src')
    4. export default components.map((filename) => {
    5. return {
    6. input: `./src/${filename}`,
    7. output: {
    8. file: `dist/${filename}`,
    9. format: 'cjs',
    10. },
    11. plugins: [babel()],
    12. }
    13. })

    打包后的结果如下所示:

    1. .
    2. ├── dist
    3. └── Button.js
    4. └── Text.js

    其中

    1. Button.js
    如下所示:
    1. 'use strict'
    2. var React = require('react')
    3. function _interopDefaultLegacy(e) {
    4. return e && typeof e === 'object' && 'default' in e ? e : {default: e}
    5. }
    6. var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
    7. var Button = function (_ref) {
    8. var children = _ref.children
    9. return /*#__PURE__*/ React__default['default'].createElement(
    10. 'button',
    11. {
    12. style: {
    13. color: 'blue',
    14. },
    15. },
    16. children
    17. )
    18. }
    19. module.exports = Button

    然后我们使用 http-server 在

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

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

    接入远程组件库

    我们使用

    1. create-react-app
    创建一个 React 应用,并新增一个
    1. DynamicComponent
    组件:
    1. const DynamicComponent = ({name, children, ...props}) => {
    2. const Component = useMemo(() => {
    3. return React.lazy(async () => fetchComponent(name))
    4. }, [name])
    5. return (
    6. <Suspense
    7. fallback={
    8. <div style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
    9. <span style={{fontSize: 50}}>Loading...</span>
    10. </div>
    11. }>
    12. <Component {...props}>{children}</Component>
    13. </Suspense>
    14. )
    15. }
    16. export default React.memo(DynamicComponent)

    这里使用到了 React 中的

    1. Suspense
    组件和
    1. React.lazy
    方法,关于他们的用法这里不做过多解释,整个
    1. DynamicComponent
    组件的含义是远程加载目标组件,这个过程该组件会渲染传入
    1. Suspense
    参数
    1. fallback
    之中的内容,最后会使用加载成功的组件进行替换。接下来看看
    1. fetchComponent
    是如何实现的:
    1. const fetchComponent = async (name) => {
    2. const text = await fetch(
    3. `http://127.0.0.1:8080/${name}.js?ts=${Date.now()}`
    4. ).then((a) => {
    5. if (!a.ok) {
    6. throw new Error('Network response was not ok')
    7. }
    8. return a.text()
    9. })
    10. const module = getParsedModule(text, name)
    11. return {default: module.exports}
    12. }

    该方法会发起网络请求得到组件的代码,并交给

    1. getParsedModule
    去解析,最后得到模块返回。我们来看一下
    1. getParsedModule
    是怎么实现的:
    1. const packages = {
    2. react: React,
    3. }
    4. const getParsedModule = (code) => {
    5. let module = {
    6. exports: {},
    7. }
    8. const require = (name) => {
    9. return packages[name]
    10. }
    11. Function('require, exports, module', code)(require, module.exports, module)
    12. return module
    13. }

    这里使用

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

    我们结合之前打包得到的

    1. Button.js
    来看这段代码,它其实同下面这个代码是等价的:
    1. const packages = {
    2. react: React,
    3. }
    4. const getParsedModule = (code, moduleName) => {
    5. let module = {
    6. exports: {},
    7. }
    8. const require = (name) => {
    9. return packages[name]
    10. }
    11. ;((require, exports, module) => {
    12. 'use strict'
    13. var React = require('react')
    14. function _interopDefaultLegacy(e) {
    15. return e && typeof e === 'object' && 'default' in e ? e : {default: e}
    16. }
    17. var React__default = /*#__PURE__*/ _interopDefaultLegacy(React)
    18. var Button = function (_ref) {
    19. var children = _ref.children
    20. return /*#__PURE__*/ React__default['default'].createElement(
    21. 'button',
    22. {
    23. style: {
    24. color: 'blue',
    25. },
    26. },
    27. children
    28. )
    29. }
    30. module.exports = Button
    31. })(require, module.exports, module)
    32. return module
    33. }

    最后我们可以按照如下方式来使用

    1. DynamicComponent
    组件:
    1. import DynamicComponent from './DynamicComponent'
    2. function App() {
    3. return (
    4. <div>
    5. <DynamicComponent name='Button'>Click Me</DynamicComponent>
    6. <DynamicComponent name='Text'>Remote Component</DynamicComponent>
    7. </div>
    8. )
    9. }
    10. export default App

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

    以上就是React远程动态组件怎么实现的详细内容,更多关于React远程动态组件怎么实现的资料请关注九品源码其它相关文章!