0

I have a constructor in my main component:

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      items: []
    } 
  };

  render() {
    return (
      <div className="App">
        <ItemList  items={this.state.items}/>       
        <AddItemForm items={this.state.items}/>
      </div>
    );
  }
}

In component AddItemForm I'm adding to array items objects with properties "item_name" that is string and "comment" with data type object. View of component:

class AddItemForm extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      item:{}  
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({item:
     {
      item_name: event.target.value,
      comment:{}
      }
    });

  }

  handleSubmit(event) {
    event.preventDefault();
    this.props.items.push(this.state.item);
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          <input type="text" item_name={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

export default AddItemForm;

How can I iterate this array to get all item_name values of every object and display them as list in my ItemList component?

1

3 Answers 3

1

This should help.

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      items: []
    } 
  };

  addItemToItemsList = (item) => {
    const {items=[]} = this.state;
    items.push(item);
    this.setState({
      items : items
    });
  }

  render() {
    return (
      <div className="App">
        <ItemList items={this.state.items}/>       
        <AddItemForm
          items={this.state.items}
          addItemToItemsList={this.addItemToItemsList}
        />
      </div>
    );
  }
}

class ItemList extends React.Component {
  render () {
    const {items} = this.props;
    return (
      <div>
        {items.map((item, index) => {
          return (
            <div key={index}>item.item_name</div>
          )
        })}
      </div>
    );
  }
}

class AddItemForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      item: {
        item_name : '',
        comment:{}
      }  
    };
  }

  handleChange = (event) => {
    const new_item = Object.assign({}, this.state.item, {item_name: event.target.value});
    this.setState({
      item: new_item
    });
  }

  handleSubmit = (event) => {
    event.preventDefault();
    this.props.addItemToItemsList(this.state.item);
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          <input type="text" item_name={this.state.item.item_name} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
export default AddItemForm;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for answer. This helped me. I took your example and changed item.item_name to {item.item_name} at ItemList component and it started work correct.
0

I think, you have an error inside AddItemForm, you should pass onSubmit function from App to AddItemForm and change items through this function:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: []
    }

    this.handleSubmit = this.handleSubmit.bind(this);
  };

  handleSubmit(value){
    this.setState({
      items: this.state.items.concat(value)
    })
  }

  render() {
    return (
      <div className="App">
        <ItemList items={this.state.items} />
        <AddItemForm 
          onSubmit={this.handleSubmit}
          items={this.state.items} />
      </div>
    );
  }
}

About main question, one of the way to solve this problem

const ItemList = ({items}) => (
  <div>
    {items.map( (item, index)=> (
      <div key={index}>{item.item_name}</div>
    ))}
  </div>
);

full working example here: https://codesandbox.io/s/7k624nz94q

Comments

0

You can't add to the array directly. You need to pass a callback that will add to the array in your parent component's state. This is a very common pattern when using react.

Here is a skeleton of what you need to do:

In your parent component, you don't need to pass the whole list to your AddItemForm component, just a addItem callback to your child component:

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      items: []
    }
    this.addItemToList = this.addItemToList.bind(this); 
  };

  render() {
    return (
      <div className="App">
        <ItemList  items={this.state.items}/>       
        <AddItemForm addItemToList={this.addItemToList}/>
      </div>
    );
  }

  addItemToList(newValue) {
    // Here you add the item to your state
    // Always treat your state as immutable, so create a copy then add the item, then set your new State
    const newArray = this.state.items.slice(); // clone
    newArray .push(newValue); // Add value
    this.setState({items: newArray}); // Set the new state
  }
}

More info on how to add items to an array in the state here: React.js - What is the best way to add a value to an array in state

Then you use that callback in your child component:

  handleSubmit(event) {
    event.preventDefault();
    // this.props.items.push(this.state.item);
    // Here don't mutate the props, instead call the callback to add the item to your parent's component's state
    this.props.addItemToList(this.state.item);
  }

To display a list of items, you need to use the map function: https://reactjs.org/docs/lists-and-keys.html#rendering-multiple-components

Comments

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.