将(外部)组件动态加载到React.js

时间:2016-11-09 10:01:49

标签: javascript reactjs frameworks

所以情况 - 我想创建将利用React和用户\第三方构建组件(Widgets)的应用程序\框架。我目前的观点是,我将有一个Root组件,它将列出加载的第三方组件。像这样:

class Root {
 constructor(p){
  this.state = {loadedWidgets: [<Chat/>, <Mail/>, <Notes/>]}
 }
 render(){
  return(
   <div>
    <Header/>
    <Body>
     {this.state.loadedWidgets.map(WidgetName => <WidgetName />)}
    </Body>
   </div>
  )
 }
}

但是我遇到了两个我无法理解或找不到解决方法的主要问题:

  1. 如果我不应该将它们硬编码到Root组件中,我将如何加载(导入)这些小部件? (我想我可以制作一些钩子,以便在用户安装小部件之后,它会以某种方式添加到状态和页面中)
  2. 为什么React不会以这种方式呈现真实的组件:
  3. (列表结束使代码标签正常工作)

     render(){
      const NameOfACustomComponent = this.state.loadedWidgets[0]
      return(<div><NameOfACustomComponent/></div>
     }
    

    渲染后,它将是一个自定义DOM标记,而不是现有的React Component。

    我想要的是构建是chrome的扩展,用用户经常使用的小窗口小部件或应用程序替换新页面,同时让开发人员可以用简单的方式添加新的窗口小部件,使用纯React.js和一些钩子用于整合。

    EDIT。找到第二个问题的答案,根据this issue React允许在你引用其类或函数(ES5 React样式)时制作任意组件。因此,2和1问题的解决方案之一是在窗口对象中有一些注册表,其中任何组件都可以自我添加并可供框架使用。虽然它应该以严格的Class实例方式来提供一个方法来添加\只删除Widget本身而不是整个列表。

2 个答案:

答案 0 :(得分:1)

你几乎在那里,改变

{this.state.loadedWidgets.map(WidgetName => <WidgetName />)}

{this.state.loadedWidgets.map(Widget => Widget)}

或者可能也应该工作:

{this.state.loadedWidgets}

答案 1 :(得分:0)

抱歉,我之前无法发布完整的解决方案。

动态组件加载的主要问题首先是警告主渲染器组件添加或删除某些DC(动态组件)的方法。第二个是较小的,可以通过一个处理组件操作的对象解决第一个来轻松修复,因此任何DC都可以添加自己,这个对象(RDCL)将提醒任何订阅者。 示例RDCL看起来像这样:

class RDCL extends Array { //so we could use filtering and stuff
  subscribe(componentType, callback) { // handle the way to notify subscriber when C. with corerct type added to RDCL }
  unsubscribe(componentType = ALL, callback) { // remove subscription }
  add(componentClassOrFunctionDefinition, [typeGoesHere?]) { // add component with default or provided or included type }
  remove(componentClassOrFunctionDefinition) { // remove component }
}

虽然动态第三方组件出现了另一个问题 - 如何处理捆绑而不包括已经包含在主app \ framework中的react和所有库。对于这个,我仍然没有答案,除了使用类型/ babel的普通脚本

如果您不需要第三方组件但希望在应用程序的任何位置动态加载它们,那么解决方案就是简单(可能非常脏):

window.ReactComponentRegistry = {}; // somewhere in root component

// some component that should be loaded dynamicaly (somewhat)
class SomeComponent exteds Component { // ... };
window.ReactComponentRegistry['SomeComponentName'] = SomeComponent;

//render() of view that would use that dynamic component
const ArbitraryComponent = window.ReactComponentRegistry.SomeComponentName // ['SomeComponentName'] obviously will work too
return(<ArbitraryComponent props={this.props} />);