ユーザー入力に基づいてさまざまなコンポーネントをレンダリングするページがあります。現時点では、以下に示すように各コンポーネントのインポートをハードコーディングしています。
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
ただし、常にコンポーネントを変更/追加しています。コンポーネントの名前とパスのみを保存し、それらを別のファイルに動的にインポートするファイルを作成する方法はありますか?
私が達成しようとしていたことに関して混乱があったのではないかと思います。私は自分が抱えていた問題をなんとか解決し、どのように解決したかを示すコードを以下に示しました。
個別のファイル(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行だけ変更するだけなので、コンポーネントを非常に迅速に追加/削除できます。
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
条件付きレンダリングを使用できます。それが役立つことを願っています
コンポーネントをマイクロアプリとしてバンドルし、URLからアプリケーションにホットロードできます。これは、サイトレベルの構成に基づいてルートからコンポーネントとマイクロアプリを動的にインポートすることをサポートするPocです。
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>
)
}
}
別のソリューションを次に示します。必要なコンポーネントのリストを取得します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(またはそのような何か)でバンドルする前にモジュールを分割する必要があります。