39

The below object is action.data has a nested object address

{
    name: 'Ben',
    address: {
        country: 'Australia',
        state: 'NSW'
    }
}

How should I handle it in the reducer?

const rootReducer = (state = initState, action) {
    switch(action.type) {
        switch RECEIVE_DATA:
            return {...state, data: action.data}
    }
}

Can I do it as above? that I just assign the whole object to data without copying?

or

const rootReducer = (state = initState, action) {
    switch(action.type) {
        switch RECEIVE_DATA:
            const address = {...action.data.address}
            const data = {...action.data, address}
            return {...state, data}
    }
}

Or should I do a deep copy of the object and assign it to data? thanks

Benjamin Li
  • 1,687
  • 7
  • 19
  • 30
  • 1
    it definitely is! If your state has several other objects/array inside of it you should definitely make a deep copy, at least the changed ones. Because of this I've been struggling what's wrong with my app for a day! – sertsedat Sep 14 '18 at 14:21

4 Answers4

33

The "correct" way to handle updates of nested data is with multiple shallow copies, one for each level of nesting. It's also certainly okay to create a new object that just replaces one field completely, per your first example.

See the Redux docs section on Immutable Update Patterns for some info on how to properly do immutable updates, and also the Redux FAQ entry regarding deep cloning.

Juan Marco
  • 3,081
  • 2
  • 28
  • 32
markerikson
  • 63,178
  • 10
  • 141
  • 157
  • "It's also certainly okay to create a new object that just replaces one field completely, per your first example" Sorry, I don't get your point. In the first exmaple, state.data.address and action.data.address are pointing to the same reference, is this fine? thanks – Benjamin Li Apr 01 '17 at 06:44
  • 6
    In other words, doing `return {...state, data : action.data}` is fine. – markerikson Apr 01 '17 at 08:04
  • dead link: "avoiding deep cloning." – stuart May 18 '20 at 21:42
22

From Redux:

Common Redux misconception: you need to deeply clone the state. Reality: if something inside doesn't change, keep its reference the same!

Emi
  • 4,597
  • 2
  • 31
  • 34
  • Take case when initialising state (using `function myReducer(state = someObject, action)`). At that stage ALL of the state is changing so deep cloning may be necessary. Specifically I found that deep cloning was necessary when having multiple instances of an app a page, to avoid data sharing between the two instances. To do that I used `function myReducer(state = { ...someObject }, action)` and made sure that `someObject` didn't contain any arrays or objects). – Andy Castles Oct 18 '18 at 13:09
  • @AndyCastles This probably means that you're mutating a prop in the state in a reducer without shallow copying it before (you're changing it, so you do need a shallow copy). You can define an initial state with `const INITIAL_STATE = {counters: [1]};` and then the reducer with `function incrementCounterReducer(state=INITIAL_STATE) { const newState = { ...state, counters: [...state.counters] }; newState.counters[0]++; return newState; }`. Then, with `console.log(INITIAL_STATE.counters, incrementCounterReducer().counters)` you'll see that we're not mutating `INITIAL_STATE.counters`. – Emi Apr 27 '19 at 17:32
0

No, shallow copy of Unchanged properties.
Changed properties will be anyway new values, so no question of type of copy.

In code we achieve it like this return {...prevState}

Akshay Vijay Jain
  • 13,461
  • 8
  • 60
  • 73
-3

If you are changing only one item in an array, Redux docs says you can use array.map, but if you know the index, this is faster:

     state[action.args.index] = {
        ...state[action.args.index],
        disregardLeafNode: action.args.checked
     }
     return state

        
Jar
  • 1,766
  • 1
  • 21
  • 27
  • Please don't do that! You are mutating the state here! You still need to do `map` and replace the concerned item. More: https://stackoverflow.com/questions/48806986/what-are-the-consequences-of-mutating-state-in-a-reducer – parse Mar 12 '22 at 12:13