0

I have multiple places in my React app where I have code like the below, just a large switch based on a format that will load the appropriate Component. Is there a way to dynamically create the component in React? Something similar to Reflection in Java, where I could do Class.instanceOf("Rule" + this.props.selectedFormatId");

renderRules() {
   switch (this.props.selectedFormatId) {
     case 1:
       return <Rules1 intl={this.props.intl} onRuleChange={this.props.onRuleChange}/>
     case 6:
       return <Rules6 intl={this.props.intl} onRuleChange={this.props.onRuleChange}/>
     case 7:
       return <Rules7 intl={this.props.intl} onRuleChange={this.props.onRuleChange}/>
       }
}

The ultimate goal is to just keep adding new Rules to the software without having to go into each of 5 places these switches appear and update them.

bluedevil2k
  • 9,366
  • 8
  • 43
  • 57
  • 1
    components are just functions, so you certainly can create them dynamically. you can also create a function which returns a class component – azium Jul 03 '19 at 20:09
  • Possible duplicate of [React / JSX Dynamic Component Name](https://stackoverflow.com/questions/29875869/react-jsx-dynamic-component-name) – rlemon Jul 03 '19 at 20:14

2 Answers2

2

Yes, it's absolutely possible. You can do something like this:

const dynamicComponents = {
  1: Rules1,
  2: Rules2,
  3: Rules3
}
const someValue = 1
const DynamicComponent = dynamicComponents[someValue]
return <DynamicComponent intl={this.props.intl} onRuleChange={this.props.onRuleChange} /> // This would be Rules1

This would render Rules1. This would mean that in order to add a new component you just need to add it to the dynamicComponents object. If you want to keep it even simpler, you could just have an array:

const dynamicComponents = [
  Rules1,
  Rules2,
  Rules3
]
const someValue = 2
const DynamicComponent = dynamicComponents[someValue]
return <DynamicComponent intl={this.props.intl} onRuleChange={this.props.onRuleChange} /> // this would be Rules2
Waclock
  • 1,686
  • 19
  • 37
  • I would need to pass in the props too. Found in another answer, the solution is to cloneElement the response component and pass in the props then. – bluedevil2k Jul 03 '19 at 21:48
  • @bluedevil2k I've edited my answer to include props, the take on this is that basically you can build a component dynamically, after defining which component you're creating you can treat it as a standard component. – Waclock Jul 04 '19 at 01:49
  • I went with adding the props in the React.createElement part rather in the "Hub" dynamic component. React.createElement(RuleHub.getRules(this.props.selectedFormatId), {intl: this.props.intl, onRuleChange:this.props.onRuleChange}) – bluedevil2k Jul 05 '19 at 15:40
1

My method to solve similar issue is to save an object literal ("map") between key and component constructor, then given the key I have a reference to the Component.

const compMap = {
  key1: require('./Component1'),
  key2: require('./Component2'),
  key3: require('./Component3'),
};

// usage of the map
renderRules() {
  const Comp = compMap[this.props.selectedFormatId];
  return (<Comp prop1="prop1" />);
}

felixmosh
  • 32,615
  • 9
  • 69
  • 88