If you just want a quick answer on how you do this, here it is:

renderElement(key, props) {
    var components = {
        'componentA': componentA,
        'componentB': componentB,
        'componentC': componentC
    }

    return React.createElement(components[key], componentProps)
}

If you want more information on how to use this more broadly and an example live implementation, read on.

Inventing a Way to Render Dynamic React Components

For the Fly Me to the Moon piece, I wanted to create a way to render output from a basic JSON-backed data store. The JSON would look something like this:

{
    "home": {
        "title": "Home Title",
        "description": "Home description",
        "content":
        [
            {
                "type": "Markdown",
                "className": "",
                "key": "header",
                "id": "header",
                "content": "Some content here"
            }
        ]
    }
}

The structure can be read as the first key is the slug for the URL, with the data inside giving the page meta data (title and description only here), and its content.

The content itself is rendered in blocks, with each block being called by one of the child objects in the content array. A block has a type, which is the React module we'll want to load to render it, and other data, which are the props we'll feed that block. Above you can see a Markdown block. Some of the other content block objects look like this:

Blocks

Rendering an Image

{
    "type": "Image",
    "className": "",
    "key": "rocket_engine",
    "id": "rocket_engine",
    "caption": "A rusty V-2 rocket engine...",
    "alt": "A rusty V-2 rocket engine",
    "src": "/fly-me-to-the-moon/piece_images/V-2_Mittelbau_engine.jpg"
}

Rendering a YouTube Video

{
    "type": "YouTube",
    "className": "",
    "key": "sputnik_video",
    "id": "sputnik_video",
    "sourceId": "KMFvr1VwSSo"
}

Rendering the Moonlanding Audio Transcript

{
    "type": "MoonLanding",
    "className": "",
    "key": "moonlanding",
    "id": "moonlanding"
}

The complexity of the data object for each block is defined by how much data is required to display what'll be inside it.

So that's all well and good, but it doesn't get us any closer to doing what we want to do - dynamically rendering blocks. For that, we turn to the following piece of code:

The PageContent Module

import React from 'react';
import Markdown from './react-markdown.js';
import Image from './react-image.js';
import Gallery from './react-gallery.js';
import YouTube from './react-youtube.js';
import MoonLanding from './react-moonlanding.js';

export default class PageContent extends React.Component {
    constructor() {
        super();

        this.renderElement = this.renderElement.bind(this);
        this.recurseElements = this.recurseElements.bind(this);
    }

    renderElement(item) {
        var components = {
            'MoonLanding': MoonLanding,
            'Markdown': Markdown,
            'Image': Image,
            'Gallery': Gallery,
            'YouTube': YouTube
        }

        return React.createElement(components[item.type], item);
    }

    recurseElements(item) {
        return (Object.prototype.toString.call(item) === '[object Array]')
            ? item.map(this.recurseElements)
            : this.renderElement(item);
    }

    render() {
        var content = [];

        for (var i = 0; i < Object.keys(this.props).length; i++) {
            content.push(this.recurseElements(this.props[i]));
        }

        return React.createElement("div", { id: "content" }, content)
    }
}

Let's unpack this a little. To start off, we import React and the content modules themselves. For the sake of completeness, I'll include the Markdown block later, so you can see an example of what one of the blocks looks like.

For now though, let's continue. We import React and the blocks we want to be able to render. We then set up a React class, which here I've called PageContent. That class sets up bindings for two functions, renderElement and recurseElements. RenderElement does what it says on the tin - we feed it an object, and in return it gives us back a React component. It does this by creating an object which maps the React components we want to output, to keys which have their names. This means we can call a component by name, and return an instance of it.

As a result, the next line does exactly that, returning a call to createElement, with the component and the data we want to pass as props as the arguments.

The second function, recurseElements, loops over our earlier JSON array (which we called content), and if it's an array, traverses deeper, otherwise it simply outputs a component.

The final function, render, sets up an array to output our content to, then pushes all the blocks on to that array. Once we've iterated over every object, we render everything inside a parent div.

In Abstract

This pattern doesn't require that a developer use the JSON based method that I outlined at the start of this post. Any data structure will do, as long as you specify the module to be rendered, and the props to be passed.

As promised earlier, here's the Markdown component used, as an example of a simple component you could render using this method:

Markdown Module

import React from 'react';
import marked from 'marked';

export default class Markdown extends React.Component {
    constructor() { super() }

    render() {
        var classes = (typeof this.props.className !== 'undefined') ? this.props.className : '';

        return React.createElement("div", { key: this.props.key, id: this.props.id, className: classes, dangerouslySetInnerjson: { __json: marked(this.props.content) } });
    }
}