[javascript] Dynamically add child components in React

My goal is to add components dynamically on a page/parent component.

I started with some basic example template like this:

main.js:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);
ReactDOM.render(<SampleComponent name="SomeName"/>, document.getElementById('myId'));

App.js:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <div id="myId">myId div</div>
            </div>

        );
    }

});

SampleComponent.js:

var SampleComponent = React.createClass({
    render: function() {
        return (
            <div>
                <h1>Sample Component! </h1>
            </div>
        );
    }
});

Here SampleComponent is mounted to <div id="myId"></div> node, which is pre-written in App.js template. But what if I need to add indefinite number of components to App component? Obviously I cannot have all the required divs sitting there.

After reading some tutorials I still have no understanding of how components are created and added to parent component dynamically. What is a way of doing it?

This question is related to javascript reactjs babeljs

The answer is


First, I wouldn't use document.body. Instead add an empty container:

index.html:

<html>
    <head></head>
    <body>
        <div id="app"></div>
    </body>
</html>

Then opt to only render your <App /> element:

main.js:

var App = require('./App.js');
ReactDOM.render(<App />, document.getElementById('app'));

Within App.js you can import your other components and ignore your DOM render code completely:

App.js:

var SampleComponent = require('./SampleComponent.js');

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component!</h1>
                <SampleComponent name="SomeName" />
            </div>
        );
    }
});

SampleComponent.js:

var SampleComponent = React.createClass({
    render: function() {
        return (
            <div>
                <h1>Sample Component!</h1>
            </div>
        );
    }
});

Then you can programmatically interact with any number of components by importing them into the necessary component files using require.


Firstly a warning: you should never tinker with DOM that is managed by React, which you are doing by calling ReactDOM.render(<SampleComponent ... />);

With React, you should use SampleComponent directly in the main App.

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);

The content of your Component is irrelevant, but it should be used like this:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <SampleComponent name="SomeName"/>
            </div>
        );
    }
});

You can then extend your app component to use a list.

var App = React.createClass({
    render: function() {
        var componentList = [
            <SampleComponent name="SomeName1"/>,
            <SampleComponent name="SomeName2"/>
        ]; // Change this to get the list from props or state
        return (
            <div>
                <h1>App main component! </h1>
                {componentList}
            </div>
        );
    }
});

I would really recommend that you look at the React documentation then follow the "Get Started" instructions. The time you spend on that will pay off later.

https://facebook.github.io/react/index.html


Sharing my solution here, based on Chris' answer. Hope it can help others.

I needed to dynamically append child elements into my JSX, but in a simpler way than conditional checks in my return statement. I want to show a loader in the case that the child elements aren't ready yet. Here it is:

export class Settings extends React.PureComponent {
  render() {
    const loading = (<div>I'm Loading</div>);
    let content = [];
    let pushMessages = null;
    let emailMessages = null;

    if (this.props.pushPreferences) {
       pushMessages = (<div>Push Content Here</div>);
    }
    if (this.props.emailPreferences) {
      emailMessages = (<div>Email Content Here</div>);
    }

    // Push the components in the order I want
    if (emailMessages) content.push(emailMessages);
    if (pushMessages) content.push(pushMessages);

    return (
      <div>
        {content.length ? content : loading}
      </div>
    )
}

Now, I do realize I could also just put {pushMessages} and {emailMessages} directly in my return() below, but assuming I had even more conditional content, my return() would just look cluttered.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to reactjs

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined raised when starting react app Template not provided using create-react-app How to resolve the error on 'react-native start' Element implicitly has an 'any' type because expression of type 'string' can't be used to index Invalid hook call. Hooks can only be called inside of the body of a function component How to style components using makeStyles and still have lifecycle methods in Material UI? React Hook "useState" is called in function "app" which is neither a React function component or a custom React Hook function How to fix missing dependency warning when using useEffect React Hook? Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release

Examples related to babeljs

Support for the experimental syntax 'classProperties' isn't currently enabled Export multiple classes in ES6 modules Getting Unexpected Token Export 'import' and 'export' may only appear at the top level Dynamically add child components in React Call async/await functions in parallel Correct way to import lodash Babel command not found ES6 exporting/importing in index file "unexpected token import" in Nodejs5 and babel?