1

I want to pass a template as props or as children and everytime I click 'add' i want to add one more item.

This is where I got so far:

App.js

<List template={
  (<Item>
      <span>Test</span>
   </Item>)
} />

List.js

...
add = () => {
    const list = this.state.list;
    const i = list.length + 1;
    const newItem = cloneElement(this.props.template, { key: i });
    this.setState({ list: this.state.list.concat([newItem]) });
}

...

render() {
    return (
      <div className="list">
        {this.state.list}
        <button onClick={this.add}>Add</button>
      </div>
    );
  }

But altough a new item is added, it has no children, so the 'Item' is there, but the 'span' is not. So the list is always empty.

Anyone knows how to do something like that?

The point is that the List mustn't be aware of what is passed to it. Whatever you pass, it should add.

2
  • stackoverflow.com/questions/36651583/… Commented Aug 18, 2018 at 3:52
  • not sure if it is the same problem. in that case SampleComponent is defined in the App component. What I want is the App component to now know about SampleComponent. It must receive it as props Commented Aug 18, 2018 at 3:57

2 Answers 2

2

Your List component only renders children. I basically do something like below

 class List extends Component{
     render(){
         return(
             <div>
                 {this.props.children}
             </div>
         )
    }
}

And you can call List and pass items or whatever like below

Your button is in the component where you call List and you pass onClick={this.add} to the button. Something like below

 this.state ={
      items: []
 }
 add = () => {
      const item =  <Item>
           <span>Test</span>
         </Item>
      this.setState(prevState => ({
           items: [...prevState.items, item]
      }));
  }
 <div>
      <List>
          {items}
      </List>
      <button onClick={this.add} />
   </div>
Sign up to request clarification or add additional context in comments.

4 Comments

but after pressing 'add' it should add one new 'Item'. This logic must be inside the List component
I updated my answer please check. This will add new item whenever add button is clicked
i just tried and what happened was what I said that the list becomes empty because the children of the child (in this case <span>) is not there.
@VictorFerreira This is because of the <Item /> component.You must make sure that the <Item /> component renders its children which were passed as a prop childrend. const Item = props => (<div className="item-container">{props.children}</div>).@Hemadri Dasari has provided you an elegant solution for your problem.He did it with proper way how to update state based on the state.If you want to use the add logic in the <List /> component you can pass the logic through the props.I think that the best idea how to improve your code would be to show all of it here or on code review.Cheers!
0
import React, { Component } from 'react';

class Item extends Component {

  render(){
    return (<p>This is an item
      {this.props.children}
    </p>)
  }

}

class List extends Component {

  constructor(props){
    super(props);
    this.state = {list: []};
  }

  add = () => {
    const list = this.state.list;
    const i = list.length + 1;
    const newItem = React.cloneElement(this.props.template, { key: i });
    this.setState({ list: this.state.list.concat([newItem]) });
    console.log(this.props.template);
  }

  render() {
    return (
      <div className="list">
        {this.state.list}
        <button onClick={this.add}>Add</button>
      </div>
    );
  }

}

class App extends Component {
  render() {
    return (
      <List template={
        (<Item>
            <span>This is a Template</span>
         </Item>)
      } />
    );
  }
}

export default App;

2 Comments

how is it different from what I Did?
not sure - didn't see your Item component - are you having it render this.props.children?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.