3

I am relatively new to React, but familiar with JavaScript. I want to make a really simple app and in JavaScript whenever I want to append a new HTML element I do something like this: document.getElementById("root").innerHTML += "<h1>Title</h1>";. In React I want to append a new MyComponent component to my page whenver my button is clicked. How can I do this in a similar way to .innerHTML +=. Below is what I have so far to give an idea, but it does not work.

index.js:

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

App.js:

function my_func() {
  var prop1 = prompt("Input here ");
  var prop2 = "new_id";
  document.getElementById("app-root").innerHTML += <MyComponent p1={ prop1 } p2={ prop2 }/>;
}

function App() {
  return (
      <div id="app-root">
      <Button color="primary" onClick={ my_func }>Add</Button>{' '}
      </div>
  );
}

export default App;
5
  • I think you should avoid directly writing html like that in React but rather have a state variable which keeps track of whether the button is clicked or not and then display your html using that state variable. Commented Oct 24, 2020 at 3:10
  • Okay, how would I do that in React? Commented Oct 24, 2020 at 3:11
  • pseudocode would be something like: const [clicked, setClicked] = useState(false); // Tracks whether clicked or not. RENDER: ... ... button OnClick = setClicked(!clicked); .... ... {clicked && YOUR HTML(JSX) } Commented Oct 24, 2020 at 3:14
  • Okay, but how would I then add the new component if it is clicked? Commented Oct 24, 2020 at 3:15
  • let me format it properly give me a sec Commented Oct 24, 2020 at 3:15

2 Answers 2

7

You should implement React State here. List of components that you will add is saved to this.state. Here is my suggestion.

This is App.js

import React, { Component } from 'react';
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      clicked: false,
      mycomponentlist:[]
    };
    this.my_func = this.my_func.bind(this);
  }
  my_func(){
     let {mycomponentlist} = this.state;
     var prop1 = prompt("Input here ");
     var prop2 = "new_id";
     mycomponentlist.push({prop1,prop2});
     this.setState({mycomponentlist,clicked:true});
  } 
  render() {
    const {clicked,mycomponentlist} = this.state;
    return (
      <div id="app-root">
         <button  onClick={this.my_func }>Add</button>
         {clicked&& mycomponentlist.map(mycomponent=> <MyComponent p1={ mycomponent.prop1 } p2={ mycomponent.prop2 }/>)}       
      </div>
    );
  }
}

export default App;

This is MyComponent.js

import React, { Component } from 'react';
class MyComponent extends Component {
    render() {
        const { p1,p2} = this.props;
        return (
            <div >
                //you can use p1,p2 here...
                <p>{p1}</p>
                <p>{p2}</p>
            </div>
        )
    }
}
export default MyComponent;

I am sure this will work. When button first clicked then clicked status becomes true so array of components are shown every render.

Sign up to request clarification or add additional context in comments.

5 Comments

I think this works, the only problem is that no matter what the prompt gets calls, rather than the prompt just being called onclick, you can't simply move the prompt to the my_func function because then prop1 does not get filled
Another issue that it does add a new component but does not append it. Therefore if I tried to add another list, it would overwrite the previous one, rather than just added another component.
@barskyn, sorry just arrived here, I understood this issue. I updated code. The first one is my fault, I have to bind my_func to this.state. So it has been solved. But what I am asking though is how are you gonna adding new component after showing MyComponent when you click button. Now I am sure it is appended under <div id="app-root">. Can you explain more detail about appending? thanks.
So basically what happens is that if I click add I do get a new MyComponent, component; however, if I try to click add again the first component just gets overwritten by the second one. What I was looking for was this functionality: click add -> new component appears -> click add again -> new component appears underneath the first new component. Hence it's an append. Does that clarify it?
I see. okay then we should array to save component list and save array to state. Let me update code.
1

Try something like this, might have to modify it a little bit according to your specific requirements.

import React,{useState} from 'react';
const App = ()=> {
    const [items, setItems] = useState([]);
    return(
      Your JSX
      {items.map((item)=> {
         return(
          <li>item</li>
         );
      })
      <button onClick={push into items}
    );
}

3 Comments

This solution somewhat works, but similar to the other answer, it adds a new component but does not append a new component. So if I added one component and then tried to add another the first component disappears rather there being two new components.
oh okay... I guess you could push your content into an array and then loop over that array to display the list. So at the beginning the empty array will not show anything and you can push elements into it from the onClick method.
Would you mind updating the solution with that? I ask only because the question is referring specifically to appending

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.