2

Ultimately I want an array of objects to render, so I start by initializing state.

state = { entries: [] };

Then I create a method that accepts an object input by the user and adds it to my array of objects.

onEntrySubmit = entry => {
    console.log(entry);
    console.log(this.state.entries);

    this.setState({ entries: [...this.state.entries, entry] })
    console.log(this.state.entries);
};

The object being passed in appears to be correct, but instead of adding this object to the array, this code replaces all existing objects with the new object. Why is this happening?

I have also tried passing the existing state to a variable and using the push method, but that did not work either.

    let temp = this.state.entries;
    temp.push(entry);
    this.setState({ entries: temp });

Here is a sandbox I made: https://codesandbox.io/s/weight-tracker-9rz95?file=/src/components/App.js

Victor
  • 65
  • 6
  • 2
    The problem is in your `Weight` component which you have not included in your question. `temp.date = event.target.value;` mutates the current state in that component, which is then passed around and mutated again later on. – Emile Bergeron Apr 28 '20 at 15:30
  • 2
    See [Why can't I directly modify a component's state, really?](https://stackoverflow.com/q/37755997/1218980) and [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/q/30782948/1218980) – Emile Bergeron Apr 28 '20 at 15:32
  • I think you mean my ```Input``` component, but thank you for the references. – Victor Apr 29 '20 at 00:14
  • Yep sorry, I skimmed quickly over the sandbox! – Emile Bergeron Apr 29 '20 at 00:50

2 Answers2

3

Use prevState value:

  onEntrySubmit = entry => {
    this.setState(prevState => {
      return {
        entries: [...prevState.entries, entry]
      };
    });
  };

Also you are mutating the state directly in you Input.js file. Spread the entry value like below, which will clone the entry value.

  onDateChange = event => {
    this.setState({ entry: { ...this.state.entry, date: event.target.value} });
  };

  onWeightChange = event => {
    this.setState({ entry: { ...this.state.entry, weight: event.target.value} });
  };

Check Working Demo

Jagrati
  • 11,474
  • 9
  • 35
  • 56
  • 2
    Or more compactly: `this.setState({ entry: { ...this.state.entry, date: event.target.value } });` – Jacob Apr 28 '20 at 15:37
1

In your sandbox, you pass in the state data from your Input Component to App Component, every time you do this, you pass the state as reference.

You need to pass a copy of that state like this:

Input.js (line 31 in your sandbox)

Instead of this.props.onSubmit(this.state.entry);

use Spread Operator like this:

 this.props.onSubmit({...this.state.entry});

Check Sandbox

Spread

zb22
  • 3,126
  • 3
  • 19
  • 34