1

Using React & Redux here:

My State looks something similar to this:

State : {
   First : {
      prop1 : "a",
      prop2 : "b"
   },
   ...
   Last : {
      prop1 : "c",
      prop2 : "d"
   }
}

My Reducer function looks like this:

const tabsState = ( state = initialTabState, action ) => {
    switch( action.type ) {
    case( ENABLE_TAB ):
        return (
            Object.assign( {}, state, action.payload )
        );
    default:
        return state;
    }
};

For the action.payload, I only want to send data containing new values for prop1. My understanding of Object.assign is that the sources parameters only update the props, they do not over-write the objects in state, is that correct?

In the above, My action.payload is similar to this:

   First : {
      prop1 : "z"
   },
   Second : {
      prop2 : "x"
   },
   ...

It seems to be overwriting the First & subsequent objects within the State object. That is to say, that the new State returned by the Reducer does not have the 2nd prop of each object. prop2s

Kayote
  • 14,579
  • 25
  • 85
  • 144
  • If you have issues with deep update state, consider changing your data structure to something else. See [this answer](http://stackoverflow.com/a/32921731/1297743) for example. Also, you can split your reducer and create special reducer for `First`, `Second` and so on. – just-boris Mar 21 '16 at 10:26

3 Answers3

2

Let's say you have a state that looks like this:

{
  state: {
    meta: {
      data: {
        foo: 'bar',
      },
    },
  },
}

And you want it to look like this:

{
  state: {
    meta: {
      data: {
        foo: 'bar',
        hello: 'world',
      },
    },
  },
}

First, create a function to update the nested property you want to get at:

const update = (data, obj) => {
  return Object.assign(
    {},
    data,
    obj,
  )
}

And then, call that update function like this:

return Object.assign(
  {},
  state,
  {
    meta: {
      data: update(state.meta.data, {hello: 'world'}),
    },
  },
)
SeanPlusPlus
  • 8,663
  • 18
  • 59
  • 84
1

I would think you could use Immutable.js. I have found it incredibly helpful for dealing with redux and not mutating the state tree. For you specific case the operator you would need to Map.mergeDeep() Where Map is your immutable data structure. MergeDeep will act just like you are thinking Object.assign will. So for you case

import { fromJS } from 'immutable';
const initialTabState = fromJS({
     {
       First : {
         prop1 : "a",
         prop2 : "b"
       },
     ...
       Last : {
         prop1 : "c",
         prop2 : "d"
       }
     }
})
const tabsState = ( state = initialTabState, action ) => {
    switch( action.type ) {
    case( ENABLE_TAB ):
        return (
            state.mergeDeep(fromJS(action.payload))
        );
    default:
        return state;
    }
};
natac
  • 342
  • 2
  • 9
0

You need to use deep assign to merge object trees like this.

https://github.com/sindresorhus/deep-assign

David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
  • Thanks for letting me know David, I was under the impression that Object.assign deep merges too. – Kayote Mar 21 '16 at 22:00