Search code examples
javascriptdomreactjsreact-dom

React AppendChild Component doesn't work


I've been looking everywhere and cannot find a solution to this.

I'm simply trying to do the following:

import ComponentOne from '../components/component-one'
import ComponentTwo from '../components/component-two'

class Home extends Component {
    constructor( props ) {
        // So I can dynamically call a Component, found no other way
        this.components = {
            ComponentOne: <ComponentOne />,
            ComponentTwo: <ComponentTwo />
        }
    }

    [...code removed for brevity...]

    _appendStep( step ) {
        var component = React.cloneElement(this.components[step])
        this.steps.appendChild( component )
    }
}

This seems pretty simple to me. I have

<div className="recipe-steps" ref={(ref) => this.steps = ref}></div>

that I need to dynamically appendChild components too. The thing is, the "steps" I append to this <div> absolutely need to be one of the components I've created, needs to allow me to add multiple component children, and even duplicate (that's why I'm using React.cloneElement()) Components.

Once I have all the "steps" appended, a later process will then parse each and every step to determine how to run a recipe.

The following works just fine, but I'm not needing to create a simple DOM node, I need to use a Component I already have built and append that

var basicElement = document.createElement('h1')
basicElement.innerHTML = "This works, but I need a component to work too"
this.steps.appendChild( basicElement )

I get the following error when I try to this.steps.appendChild( component ):

Error:

Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

I guess my main question is this: how can I convert my React Component into a node that can be used with this.steps.appendChild()?

OR: is there a "React way" to dynamically append children components to my this.steps?


Solution

  • this.steps should be an array, then, you will be able to render that array using the map function.

    Also you should store your array in your state in order to auto re-render the component after you add new steps.

    It should look like this

     constructor( props ) {
        this.state = {
           steps: []
         }
        this.components = {
            ComponentOne: <ComponentOne />,
            ComponentTwo: <ComponentTwo />
        }
    }
    _appendStep( step ) {
            let componentToAdd= this.components[step];
            this.setState({steps: this.state.steps.concat([componentToAdd])})
        }
    
    render(){
         ....
        {this.state.steps.map(function(comp,i){
            return <div key={'Step' + i}>{comp}</div>
        })}
    
    }