繁体   English   中英

动态加载 React 组件

[英]Dynamically loading React components

我正在考虑构建一个 Web 应用程序,人们可以在其中安装插件。 我希望插件能够定义将呈现到页面的 React 组件,而无需在安装插件后重新编译主 JavaScript 包。

所以这是我正在考虑的方法:

  • 使用 webpack 将主要 JavaScript 与 React 作为外部库捆绑在一起。
  • 让插件作者也使用 React 作为外部库编译他们的组件。

这样,我只运行了一个 React 实例。 我可能可以对其他一些经常使用的库做同样的事情。

那么问题是如何从服务器动态加载这些插件组件。 假设我有以下组件:

class PluginRenderer extends React.Component{
  componentWillMount() {
    getPluginComponent(`/plugins/${this.props.plugin}/component.js`).then((com) => {
      this.setState({pluginComponent: com});
    })
  }

  render() {
    var Plugin = this.state.pluginComponent;
    return Plugin ? <Plugin {...this.props} /> : "Loading..."
  }
}

如何实现getPluginComponent

这是几个月前我在客户工作中也面临的一个有趣问题,我没有看到太多的文档方法。 我们所做的是:

  1. 单个插件将是单独的 Webpack 项目,我们为其提供模板或生成项目模板的 CLI 工具。

  2. 在这个项目中,我们为核心应用程序中已经使用的共享供应商库定义了 Webpack externals :React、Redux 等。这告诉插件不要将它们包含在包中,而是从我们在核心应用程序中设置的window的变量中获取它们. 我知道,听起来很糟糕,但这比让所有插件重新包含 1000 个共享模块要好得多。

  3. 重用这个external概念,核心应用程序还通过 window 对象向插件提供了一些服务。 最重要的一个是PluginService.register()方法,您的插件在初始化时必须调用该方法。 我们在这里反转控制:插件负责向核心应用程序说“嗨,我在这里,这是我的主要导出(组件,如果它是 UI 插件)”。

  4. 核心应用程序有一个 PluginCache 类/模块,它只保存加载插件的缓存(pluginId -> 无论插件导出,fn,类,等等)。 如果某些代码需要一个插件来呈现,它会向这个缓存请求它。 这样做的好处是允许在插件未正确加载时返回<Loading /><Error />组件,等等。

  5. 对于插件加载,这个 PluginService/Manager 加载插件配置(我应该加载哪些插件?)然后创建动态注入的script标签来加载每个插件包。 当 bundle 完成时,第 3 步中描述的register调用将被调用,第 4 步中的缓存将包含该组件。

  6. 不要尝试直接从您的组件加载插件,而是从缓存中请求它。

这是一个非常高级的概述,它与我们当时的需求密切相关(它是一个类似仪表板的应用程序,用户可以在其中动态添加/删除面板,并且所有这些小部件都是作为插件实现的)。

根据您的情况,您甚至可以使用<Provider store={ theCoreStore } > 包装插件,以便它们必须访问 Redux,或者设置某种事件总线,以便插件可以相互交互......有很多东西要提前弄清楚。 :)

祝你好运,希望它以某种方式有所帮助!

您可以导入一个 HOC 组件来执行此操作。 组件作为微型应用程序动态加载到您的主机应用程序中。

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

window.React = React;
window.ReactDOM = ReactDOM;

ReactDOM.render(<App />, document.getElementById('root'));

// app.js
import React from 'react';
import ReactDOM from 'react-dom';
import MicroApp from '@schalltech/honeycomb-react-microapp';

const App = () => {
  return (
    <MicroApp
        config={{
          View: {
            Name: 'redbox-demo',
            Scope: 'beekeeper',
            Version: 'latest'
          }
        }}
      />
  );
});

export default App;

这些组件在设计时未安装或已知。 如果您有创意,使用这种方法您可以更新您的组件,而无需重新部署您的主机应用程序。

https://github.com/Schalltech/honeycomb-marketplace#using-micro-apps

在一个类似的问题上提出了另一种方法 回顾:

在您的应用上

import(/* webpackIgnore: true */'https://any.url/file.js')
  .then((plugin) => {
    plugin.main({ /* stuff from app plugins need... */ });
  });

在你的插件...

const main = (args) => console.log('The plugin was started.');
export { main };
export default main;

在其他问题的页面上查看更多详细信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM