J'essaie de rendre dynamiquement les composants en fonction de leur type.
Par exemple:
var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent /> instead of <ExampleComponent />
J'ai essayé la solution proposée ici noms des composants dynamiques React/JSX
Cela m'a donné une erreur lors de la compilation (en utilisant browserify pour gulp). Il s’attendait à ce que XML utilise une syntaxe de tableau.
Je pourrais résoudre ce problème en créant une méthode pour chaque composant:
newExampleComponent() {
return <ExampleComponent />;
}
newComponent(type) {
return this["new" + type + "Component"]();
}
Mais cela signifierait une nouvelle méthode pour chaque composant que je crée. Il doit y avoir une solution plus élégante à ce problème.
Je suis très ouvert aux suggestions.
<MyComponent />
est compilé en React.createElement(MyComponent, {})
, qui attend une chaîne (balise HTML) ou une fonction (ReactClass) comme premier paramètre.
Vous pouvez simplement stocker votre classe de composants dans une variable dont le nom commence par une lettre majuscule. Voir balises HTML vs React Components .
var MyComponent = Components[type + "Component"];
return <MyComponent />;
compile pour
var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
Une documentation officielle sur la façon de gérer de telles situations est disponible ici: https://facebook.github.io/react/docs/jsx-in-depth.html#choosing-the-type-at-runtime
En gros, il est écrit:
Faux:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}
Correct:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
J'ai trouvé une nouvelle solution. Notez que j'utilise des modules ES6 et que j'ai donc besoin du cours. Vous pouvez également définir une nouvelle classe React.
var components = {
example: React.createFactory( require('./ExampleComponent') )
};
var type = "example";
newComponent() {
return components[type]({ attribute: "value" });
}
Si vos composants sont globaux, vous pouvez simplement faire:
var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});
Pour un composant wrapper, une solution simple consisterait simplement à utiliser React.createElement
directement (à l'aide de ES6).
import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'
class Button extends React.Component {
render() {
const { type, ...props } = this.props
let button = null
switch (type) {
case 'flat': button = FlatButton
break
case 'icon': button = IconButton
break
default: button = RaisedButton
break
}
return (
React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
)
}
}
Un conteneur doit mapper les noms de composants sur tous les composants censés être utilisés de manière dynamique. Les classes de composants doivent être enregistrées dans un conteneur, car dans un environnement modulaire, il n’existe pas d’autre endroit unique pour y accéder. Les classes de composants ne peuvent pas être identifiées par leurs noms sans les spécifier explicitement car la fonction name
est réduite en production.
Ce peut être un objet simple:
class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
Ou Map
instance:
const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);
L'objet brut est plus approprié car il bénéficie d'un raccourci de propriété.
Un module baril avec les exportations nommées peut agir comme tel:
// Foo.js
export class Foo extends React.Component { ... }
// dynamic-components.js
export * from './Foo';
export * from './Bar';
// some module that uses dynamic component
import * as componentsMap from './dynamic-components';
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
Cela fonctionne bien avec une classe par style de code de module.
Les décorateurs peuvent être utilisés avec des composants de classe pour le sucre syntaxique. Cela nécessite néanmoins de spécifier explicitement les noms de classe et de les enregistrer dans une carte:
const componentsMap = {};
function dynamic(Component) {
if (!Component.displayName)
throw new Error('no name');
componentsMap[Component.displayName] = Component;
return Component;
}
...
@dynamic
class Foo extends React.Component {
static displayName = 'Foo'
...
}
Un décorateur peut être utilisé comme composant d'ordre supérieur avec des composants fonctionnels:
const Bar = props => ...;
Bar.displayName = 'Bar';
export default dynamic(Bar);
L'utilisation de non standard displayName
au lieu de la propriété aléatoire est également bénéfique pour le débogage.
Nous souhaitons accéder à différentes vues lors du chargement dynamique des composants. Le code suivant donne un exemple de travail sur la façon de procéder en utilisant une chaîne analysée à partir de la chaîne de recherche d'une URL.
Supposons que nous souhaitons accéder à une page 'snozberrys' avec deux vues uniques utilisant ces chemins d'URL:
'http://localhost:3000/snozberrys?aComponent'
et
'http://localhost:3000/snozberrys?bComponent'
nous définissons le contrôleur de notre vue comme ceci:
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router,
Route
} from 'react-router-dom'
import AComponent from './AComponent.js';
import CoBComponent sole from './BComponent.js';
const views = {
aComponent: <AComponent />,
console: <BComponent />
}
const View = (props) => {
let name = props.location.search.substr(1);
let view = views[name];
if(view == null) throw "View '" + name + "' is undefined";
return view;
}
class ViewManager extends Component {
render() {
return (
<Router>
<div>
<Route path='/' component={View}/>
</div>
</Router>
);
}
}
export default ViewManager
ReactDOM.render(<ViewManager />, document.getElementById('root'));
J'ai utilisé une approche un peu différente, car nous connaissons toujours nos composants réels et j'ai donc pensé à appliquer le boîtier d'interrupteur. En outre, le nombre total de composants était d'environ 7-8 dans mon cas.
getSubComponent(name) {
let customProps = {
"prop1" :"",
"prop2":"",
"prop3":"",
"prop4":""
}
switch (name) {
case "Component1": return <Component1 {...this.props} {...customProps} />
case "Component2": return <Component2 {...this.props} {...customProps} />
case "component3": return <component3 {...this.props} {...customProps} />
}
}