web-dev-qa-db-ja.com

React-コンポーネントを動的にインポートする

ユーザー入力に基づいてさまざまなコンポーネントをレンダリングするページがあります。現時点では、以下に示すように各コンポーネントのインポートをハードコーディングしています。

    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

ただし、常にコンポーネントを変更/追加しています。コンポーネントの名前とパスのみを保存し、それらを別のファイルに動的にインポートするファイルを作成する方法はありますか?

12
LEJ

私が達成しようとしていたことに関して混乱があったのではないかと思います。私は自分が抱えていた問題をなんとか解決し、どのように解決したかを示すコードを以下に示しました。

個別のファイル(ComponentIndex.js):

    let Components = {};

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

    export default Components

メインファイル(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

この方法では、インポートが1つのファイルにあり、一度に1行だけ変更するだけなので、コンポーネントを非常に迅速に追加/削除できます。

16
LEJ
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

条件付きレンダリングを使用できます。それが役立つことを願っています

チェックしてください

1
user8685433

コンポーネントをマイクロアプリとしてバンドルし、URLからアプリケーションにホットロードできます。これは、サイトレベルの構成に基づいてルートからコンポーネントとマイクロアプリを動的にインポートすることをサポートするPocです。

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

1
Eric Schall

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>
    )
}

}

0

別のソリューションを次に示します。必要なコンポーネントのリストを取得します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>
        )
    }

したがって、アプリがロードされると、必要なモジュールがプルされます。

promisesを使用してそれらをインポートしようと考えましたが、モジュールはすでに約束されています。

最近サーバーからそれらをajaxする必要がある場合、require(またはそのような何か)でバンドルする前にモジュールを分割する必要があります。

0
AlexNikonov