React — Dynamic Component Names with JSX
Using components within other components is one of the most common things you will do working with React. What happens when you need a more elegant solution for conditionally rendering these though?
If and switch statements can do the job fine for a predefined list of components, but what if you want to set it directly based on a prop passed into the parent component?
Your initial idea may be to do something similar to what is shown below. Attempting to set the tag name (directly) via a general expression. This wont work and will cause a compiler error.
render() {
return <[this.props.tag] />
}
You can’t use a general expression to do this, its not how JSX works. Element names that start with a lowercase letter refers to built in components (or HTML elements) such as div and span tags.
In React, names starting with a capital letter will compile to the createComponent method. So with that in mind, the correct solution is to assign the name value to a capitalized variable (see below).
render() {
const TagName = this.props.tag;
return <TagName />
}
Another technique I like to use is mapping child components in an object. This makes the component easier to configure (and reuse) as only an abbreviated key is required instead of the full component name.
import React, { Component } from 'react';
import FooComponent from './foo-component';
import BarComponent from './bar-component';class MyComponent extends Component { components = {
foo: FooComponent,
bar: BarComponent
}; render() {
const TagName = this.components[this.props.tag || 'foo'];
return <TagName />
}
}export default MyComponent;
If further child components are added in the future another item can be added to this map. Keep in mind the value assigned can be a component or class reference, not just a string.
The component can then be imported and used as shown below.
import React, { Component } from 'react';
import MyComponent from './my-component';class App extends Component { render() {
return (
<div>
<MyComponent tag="foo" />
<MyComponent tag="bar" />
</div>
);
}}export default App;