React in the form we usually see doesn't really look like it can make components dynamically. Most people end up using switch
with case
blocks to "choose" the type of component that will be rendered when there are multiple possibilities, which I'd say is an anti-pattern.
For example:
We don't want to have to have that switch statement ... as the number of components we might output grows, it's going to start getting really ugly and hard to maintain. The page JSX in Depth in the React documentation holds the key to understanding how to create components dynamically instead, in the section marked "Choosing the Type at Runtime". That page doesn't come up high in searches, though, and it doesn't do a very good job of explaining the technique.
I like to call this technique the Capitalized reference technique.
Here's an explanation of how to use the technique:
- Import the components we might use
- Add references to the components to an object literal
- Create a reference to the dynamic component type we want by:
- Creating a new variable (reference) with a first letter that is Capitalized
- Using the component type as the key, get the corresponding value from the object literal
- Assign the value from the literal, a reference to the component, to the Capitalized reference
- Include the dynamic component using the Capitalized reference from step 3.1 in our JSX.
The fundamental 'magic' here is that when JSX sees the Capitalized reference, it dereferences back to whatever component the reference is pointed at. Yay references!
In the simplest form:
Requiring us to import any component we might want to render and add it to an object literal isn't very maintainable. We want to keep the list of possible components to render outside of this dynamic component renderer. To do that, we'll send a components dictionary in as part of props
. After we externalize the set of possible components to render, we'll achieve good maintainability.
We probably aren't rendering just one component this way, but rendering a wrapper around any number of dynamically-defined children. To work on a collection of dynamic component instances, we need to:
- Iterate over the collection in JSX
- For each item:
- Reassign the value we get from
Components[ component.type ]
to the Capitalized reference we've created - Use that Capitalized reference in our JSX in order to render the correct component type
- Reassign the value we get from
The method for iterating over a collection in JSX is also covered on the page JSX in Depth, this time in a section titled "javascript expressions as children".
Now that we can easily render components based on a configuration, we've achieved a basic kind of polymorphism -- the type of a component can be changed by changing a value in props. Doing it based off of a collection proves that we can use any kind of technique that walks an object tree to render a hierarchy in order to achieve composition. The arrangement and functioning of an application can be driven based on the collection.
A complete sample project and demo can be found here: react-dynamic-component-demo.