0

I feel like my reducer should be working, but it keeps insisting that I'm mutating the state.

Uncaught Error: A state mutation was detected inside a dispatch, in the path: output.outputList.0.composition. Take a look at the reducer(s) handling the action {"type":"SET_OUTPUT_COMPOSITION",

I posted something similar a couple hours ago with no answers, but I figured my redux state was too complicated. This is my simplified version and I'm still getting mutate errors.. what am I doing wrong? should I not be using a class in my redux state? should i be using some sort of immutable library? please help me.

My Initial Redux State

output: {
    outputList: [], //composed of Output class objects
    position: 0
  }

Output Class

class Output {

  constructor(output) {
      this.id = output.id;
      this.composition = output.getComposition();
      this.outputObj = output;
      this.name = output.name;
      this.url = output.getUrl();    
  }
}

export default Output;

Reducer for updating property

case types.SET_OUTPUT_COMPOSITION: {
      let outputListCopy = Object.assign([], [...state.outputList]);
      outputListCopy[state.position].composition = action.composition;
      return Object.assign({}, state, {outputList: outputListCopy});

Action

export function setOutputComposition(comp) {
 return { type: types.SET_OUTPUT_COMPOSITION, composition: comp}
}
user1189352
  • 3,628
  • 12
  • 50
  • 90

2 Answers2

1

The spread operator does not deep copy the objects in your original list:

let outputListCopy = Object.assign([], [...state.outputList]);

It is a shallow copy, therefore

outputListCopy[state.position].composition = action.composition;

You are actually mutating previous state objects, as you said in your comment there are several ways to work around this, using slice/splice to create new instance of the array, etc.

You can also take a look at using ImmutableJS, in general I would say storing classes in the redux store makes the thing a bit hard to understand, I tend to favor simple structures that can be easily inspected with redux-tools.

Oscar Franco
  • 5,691
  • 5
  • 34
  • 56
0

The error is coming from dispatch. So it not even getting as far as the reducer. I expect it does not like you using class to define output. Instead just do const output ={ ... }.

David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
  • ah i was hoping you would be correct.. i turned the class into a psuedo class where it's a function that just returns an object with the same properties but still getting the same error. Also when I put a break point in the reducer, I see it go all the way through, it gets the same error though when once it tries to return the new state as did before. – user1189352 Mar 16 '17 at 17:41
  • What happens if you send a string instead? – David Bradshaw Mar 16 '17 at 17:58