Javascript React - 动态导入组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48268507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:03:41  来源:igfitidea点击:

React - Dynamically Import Components

javascriptreactjsimportcomponentsreact-component

提问by LEJ

I have a page which renders different components based on user input. At the moment, I have hard coded the imports for each component as shown below:

我有一个页面,它根据用户输入呈现不同的组件。目前,我已经对每个组件的导入进行了硬编码,如下所示:

    import React, { Component } from 'react'
    import Component1 from './Component1'
    import Component2 from './Component2'
    import Component3 from './Component3'

    class Main extends Component {
        render() {
            var components = {
                'Component1': Component1,
                'Component2': Component2,
                'Component3': Component3
            };
            var type = 'Component1';  // just an example
            var MyComponent = Components[type];
            return <MyComponent />
        }
    }

    export default Main

However, I change/add components all the time. Is there a way to perhaps have a file which stores ONLY the names and paths of the components and these are then imported dynamically in another file?

但是,我一直在更改/添加组件。有没有办法让文件只存储组件的名称和路径,然后将它们动态导入到另一个文件中?

回答by LEJ

I think there may have been some confusion as to what I was trying to achieve. I managed to solve the issue I was having and have shown my code below which shows how I solved it.

我认为可能对我试图实现的目标有些困惑。我设法解决了我遇到的问题,并在下面显示了我的代码,其中显示了我是如何解决它的。

Separate File (ComponentIndex.js):

单独的文件(ComponentIndex.js):

    let Components = {};

    Components['Component1'] = require('./Component1').default;
    Components['Component2'] = require('./Component2').default;
    Components['Component3'] = require('./Component3').default;

    export default Components

Main File (Main.js):

主文件(Main.js):

    import React, { Component } from 'react';
    import Components from './ComponentIndex';

    class Main extends Component {
        render () {
            var type = 'Component1'; // example variable - will change from user input
            const ComponentToRender = Components[type];
            return <ComponentToRender/>
        }
    }

    export default Main

This method allows me to add/remove components very quickly as the imports are in one file and only requires changing one line at a time.

这种方法允许我非常快速地添加/删除组件,因为导入在一个文件中并且一次只需要更改一行。

回答by user8685433

import React, { Component } from 'react'
import Component1 from './Component1'
import Component2 from './Component2'
import Component3 from './Component3'

class Main extends Component {
    render() {
        var type = 'Component1';  // just an example
        return (
          <div>
            {type == "Component1" && <Component1 />}
            {type == "Component2" && <Component2 />}
            ...
          </div>
        )
    }
}

export default Main

You can use conditional rendering insted. Hope it will help

您可以使用条件渲染插入。希望它会有所帮助

Check this

检查这个

回答by Eric Schall

You can bundle your components as micro-apps and hot load them into your application from a url. Here is a poc that supports dynamically importing components and micro-apps from a route based on a configuration on the site level.

您可以将您的组件捆绑为微应用程序,并从 url 将它们热加载到您的应用程序中。这是一个支持从基于站点级别配置的路由动态导入组件和微应用程序的 poc。

https://github.com/eschall/react-micro-frontend

https://github.com/eschall/react-micro-frontend

回答by Leo

Since the question is really old, the answers maybe were ok. But nowadays, if someone have the same problem should use dynamic import, in order to load only the component needed and avoid to load all the different ones.

由于问题真的很老,所以答案可能还可以。但是现在,如果有人遇到同样的问题应该使用动态导入,以便只加载需要的组件并避免加载所有不同的组件。

const component = React.lazy(() => import('./component.jsx'));

try the example here: demo

试试这里的例子:演示

回答by Eric Hasselbring

you could create a component building function that utilizes React.createElement. this way you can import the function from a helper file. hard to show more code in this example without more information, but you can use state helpers from this file too if your goal is to completely remove the logic from this component.

您可以创建一个使用React.createElement的组件构建函数。这样您就可以从帮助文件中导入该函数。在没有更多信息的情况下,很难在此示例中显示更多代码,但是如果您的目标是从该组件中完全删除逻辑,您也可以使用此文件中的状态助手。

class Main extends Component {

constructor(props) {
  super();
  this.state = { displayComponent: Component1 }
}

buildComponent = () => {
  // create element takes additional params for props and children
  return React.createElement( this.state.displayComponent )
}

render() {
    var type = 'Component1';  // just an example
    return (
      <div>
        { this.buildComponent() }
      </div>
    )
}

}

}

回答by AlexNikonov

Here is another solution: We get the list of needed components list = ['c1', 'c2', 'c3']. It may be pulled from json file to an array (i use redux-store so i initiate getting forms by this.props.getForms()). But you may just create and access the list of components manually.

这是另一个解决方案:我们得到所需组件的列表list = ['c1', 'c2', 'c3']。它可以从 json 文件拉到一个数组(我使用 redux-store 所以我开始通过 this.props.getForms() 获取表单)。但是您可以手动创建和访问组件列表。

    componentDidMount = () => {
//we get elements list from any source to redux-store
        this.props.getForms();
//access redux-store to the list
        const forms = this.props.configBody.sets;
//make deep object copy
        const updatedState = { ...this.state };
        updatedState.modules = [];
        if (forms) {
//here is the very dynamic import magic: we map the import list and prepare to store the imports in Component`s state
            const importPromises = forms.map(p =>
                import(`../TemplateOrders/Template${p.order}`)
                    .then(module => {
                        updatedState.modules.push(module.default)
                    })
                    .catch(errorHandler(p))
            )
//wait till all imports are getting resolved
            Promise.all(importPromises)
                .then(res =>
//then run setState
                    this.setState({ ...updatedState }, () => {
                        console.log(this.state);
                    }))
        }
    }

    render() {
        const forms = this.props.configBody.sets;
//we iterate through the modules and React.createElemet`s 
        const list = this.state.modules
            ? this.state.modules.map((e, i) =>
                createElement(e, { key: forms[i].title }, null)
            )
            : [];
        return (
            <Fragment>
                <Link to='/'>Home</Link>
                <h1>hello there</h1>
//push them all to get rendered as Components
                {list.map(e => e)}
            </Fragment>
        )
    }

So when your app is loaded it pulls the needed modules.

因此,当您的应用程序加载时,它会拉取所需的模块。

I thought to use promisesto import them, but modules are already promises.

我想使用承诺来导入它们,但模块已经是承诺。

In case we need to ajax them from server lately, so we need to split the modules before bundling with require(or something like that) dont know exactly.

在情况下,我们需要从最近的服务器阿贾克斯它们,所以我们需要绑定前的模块分割要求(或类似的东西),不知道到底。