Ich habe eine Seite, die verschiedene Komponenten basierend auf Benutzereingaben darstellt. Im Moment habe ich die Importe für jede Komponente wie folgt fest codiert:
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
Ich verändere/füge jedoch ständig Komponenten hinzu. Gibt es eine Möglichkeit, eine Datei zu haben, die NUR die Namen und Pfade der Komponenten speichert und diese dann dynamisch in eine andere Datei importiert werden?
Ich glaube, es gab einige Verwirrung darüber, was ich erreichen wollte. Ich konnte das Problem lösen, das ich hatte, und habe unten meinen Code gezeigt, der zeigt, wie ich es gelöst habe.
Separate Datei (ComponentIndex.js):
let Components = {};
Components['Component1'] = require('./Component1').default;
Components['Component2'] = require('./Component2').default;
Components['Component3'] = require('./Component3').default;
export default Components
Hauptdatei (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
Mit dieser Methode kann ich sehr schnell Komponenten hinzufügen/entfernen, da die Importe in einer Datei sind und nur jeweils eine Zeile geändert werden muss.
Sie können Ihre Komponenten als Mikro-Apps bündeln und über eine URL im laufenden Betrieb in Ihre Anwendung laden. Hier ist ein POC, der das dynamische Importieren von Komponenten und Mikro-Apps von einer Route basierend auf einer Konfiguration auf Site-Ebene unterstützt.
sie könnten eine Komponentenerstellungsfunktion erstellen, die React.createElement verwendet. Auf diese Weise können Sie die Funktion aus einer Hilfsdatei importieren. In diesem Beispiel ist es schwierig, mehr Code ohne weitere Informationen anzuzeigen. Sie können jedoch auch Statushilfen aus dieser Datei verwenden, wenn Sie die Logik vollständig aus dieser Komponente entfernen möchten.
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>
)
}
}
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
Sie können das bedingte Rendering insted verwenden. Ich hoffe es wird helfen
Hier ist eine andere Lösung: Wir erhalten die Liste der benötigten Komponenten list = ['c1', 'c2', 'c3']
. Es kann von der JSON-Datei in ein Array gezogen werden (ich verwende Redux-Store, damit ich das Abrufen von Formularen durch this.props.getForms () initiiere). Sie können die Liste der Komponenten jedoch nur manuell erstellen und aufrufen.
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>
)
}
Wenn Ihre App geladen ist, werden die erforderlichen Module abgerufen.
Ich dachte, ich verwende Versprechen , um sie zu importieren, aber Module sind bereits Versprechen.
Für den Fall, dass wir sie in letzter Zeit vom Server entfernen müssen, müssen wir die Module aufteilen, bevor wir sie mit require (oder so ähnlich) bündeln.