动态加载React组件 [英] Dynamically loading React components

查看:175
本文介绍了动态加载React组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm thinking about building a web application, where people can install plugins. I'd like plugins to be able to define React components that will be rendered to the page, without recompiling the main JavaScript bundle after installing the plugin.

所以这是方法我在考虑:

So here's the approach I'm thinking of:


  • 将主要JavaScript与React捆绑为外部库,使用webpack。

  • 让插件作者用React编译他们的组件作为外部库。

  • Bundle the main JavaScript with React as an external library, using webpack.
  • Have plugin authors compile their components with React as an external library as well.

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

This way, I'm only running one instance of React. I could probably do the same with some other frequently used libraries.

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

The problem then, is how to dynamically load these plugin components from the server. Let's say I have the following component:

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 可以实现吗?

推荐答案

这是我几个月前遇到的一个有趣的问题对于客户工作,我没有看到太多的文档方法。我们做的是:

It's an interesting problem I also faced some months ago for customer work, and I didn't see too many document approaches out there. What we did is:


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

  1. Individual plugins will be separate Webpack projects, for which we provide either a template or a CLI tool that generates project templates.

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

In this project we define Webpack externals for shared vendor libraries already used in the core application: React, Redux, etc. This tells the plugin to not include those in the bundle but to grab them from a variable in window we set in the core app. I know, sounds like sucks, but it's much better than having all plugins re-include 1000s of shared modules.

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

Reusing this concept of external, the core app also provides some services via window object to plugins. Most important one is a PluginService.register() method which your plugin must call when it's initialized. We're inverting control here: the plugin is responsible to say "hi I'm here, this is my main export (the Component if it's a UI plugin)" to the core application.

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

The core application has a PluginCache class/module which simply holds a cache for loaded plugins (pluginId -> whatever the plugin exported, fn, class, whatever). If some code needs a plugin to render, it asks this cache for it. This has the benefit of allowing to return a <Loading /> or <Error /> component when a plugin did not load correctly, and so on.

对于插件加载,这个PluginService / Manager加载插件配置(我应该加载哪些插件?)和然后创建动态注入的脚本标签来加载每个插件包。捆绑完成后,将调用步骤3中描述的 register 调用,并且步骤4中的缓存将包含该组件。

For plugin loading, this PluginService/Manager loads the plugin configuration (which plugins should I load?) and then creates dynamically injected script tags to load each plugin bundle. When the bundle is finished, the register call described in step 3 will be called and your cache in step 4 will have the component.

而不是尝试直接从组件加载插件,而是从缓存中请求插件。

Instead of trying to load the plugin directly from your component, ask for it from the cache.

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

This is a very high level overview which is pretty much tied to our requirements back then (it was a dashboard-like application where users could add/remove panels on the fly, and all those widgets were implemented as plugins).

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

Depending on your case, you could even wrap the plugins with a <Provider store={ theCoreStore }> so they have to access to Redux, or setup an event bus of some kind so that plugins can interact with each other... There is plenty of stuff to figure out ahead. :)

祝你好运,希望它有所帮助!

Good luck, hope it helped somehow!

这篇关于动态加载React组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆