0

I have this set of data

this.state = { weeks: [ { weekNumber: 1, weights: [] }, { weekNumber: 2, weights: [] } ] }

What I want to do is create a new array and set it to 'weights'. I've checked other posts like this one: Set state of nested array

I assume I do something similar.

Edit: Also, say for instance I want to update each individual week's weights array, how would I go about doing that?

Bpicks
  • 33
  • 1
  • 5
  • Are you trying to create a new entry in state called "weights" or create a variable called "weights"? – Cody Swann Apr 04 '19 at 01:02
  • @CodySwann I figured I would create a new array variable and use that new array variable to update the state 'weights' – Bpicks Apr 04 '19 at 01:06
  • 1
    @Bpicks - take a look at react's immutability helpers—specifically, the update method. You can create a new state object and then use setState to update your entire state with the updated state. https://reactjs.org/docs/update.html – heyitsjhu Apr 04 '19 at 01:10
  • @heyitsjhu beat me to it. That's the best way. Otherwise, you have to do some nasty object extensions with the spread operator – Cody Swann Apr 04 '19 at 01:19
  • @CodySwann `@heyitsjhu Ok, say for instance I want to update both weeks' weights' arrays. Would I just map through each week and update the state using the update method from immutability helpers? – Bpicks Apr 04 '19 at 01:42

2 Answers2

1

I usually use this solution:

const newWeeks = [ ...this.state.weeks ];
newWeeks[0] = { ...newWeeks[0] };
//modify `newWeeks`

this.setState({
  weeks: newWeeks
});

Update 1: Live version: https://codesandbox.io/s/20v7r2zx0j?fontsize=14&module=%2Fsrc%2FTest.js


Update 2: thank @bird. Problem is Spread only goes one level deep when copying an array(or object), so we need an extra step here:

newWeeks[0] = { ...newWeeks[0] };
namth
  • 2,747
  • 1
  • 9
  • 17
  • This is not the way to clone a nested object. The weight property still a reference. Modified the `newWeeks[0].weight` cause change to `this.state.weeks[0].weight` also. – bird Apr 04 '19 at 02:06
  • Hi, you can see I created new array from old array using **Spread syntax**, It create new array with value, not reference, read more about it here > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – namth Apr 04 '19 at 02:15
  • Just put `console.log(this.state.weeks);` at line 21 in your code sandbox, right after the `newWeeks[0].weights = [1, 2, 3];` line. You will see the `weeks[0].weights` also modified, when `setState` action doesn't run yet. – bird Apr 04 '19 at 02:20
0

Because it's a nested object, then you can clone with native javascript code with JSON.parse(JSON.stringify(obj))

this.state = {
    weeks: [
        {
            weekNumber: 1,
            weights: []
        },
        {
            weekNumber: 2,
            weights: []
        }
    ]
}

const newWeeks = JSON.parse(JSON.stringify(this.state.weeks))

newWeeks[0].weights = [1,2,3]

this.setState({weeks: newWeeks})

The other normal clone like: [...this.state.weeks] or Object.assign([], this.state.weeks) only clone properties of level 1 not the nested, in your case, the weight property will not be cloned, just copied the reference in a normal way.

You can take a look at cloneDeep of lodash lib or use immer to archive your goal, also.

bird
  • 1,872
  • 1
  • 15
  • 32