using …spread, but redux still throws warning abou

2019-04-01 04:00发布

问题:

Redux throws Warning on dispatch:

Error: A state mutation was detected inside a dispatch, in the path: 
roundHistory.2.tickets. Take a look at the reducer(s) handling the action {"type":"ARCHIVE_TICKETS","roundId":"575acd8373e574282ef18717","data":[{"_id":"575acd9573e574282ef18718","value":7,"user_id":"574c72156f355fc723ecdbbf","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575acd9573e574282ef18719","value":9,"user_id":"574c72156f355fc723ecdbbf","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575acd9573e574282ef1871a","value":8,"user_id":"574c72156f355fc723ecdbbf","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575acdac73e574282ef1871b","value":19,"user_id":"574c72156f355fc723ecdbbf","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575ad50c4c17851c12a3ec23","value":29,"user_id":"57522f0b1f08fc4257b9cbc6","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575ad50c4c17851c12a3ec24","value":28,"user_id":"57522f0b1f08fc4257b9cbc6","round_id":"575acd8373e574282ef18717","__v":0},{"_id":"575ad

The only reducer handling ARCHIVE_TICKETS action is this one:

case 'ARCHIVE_TICKETS' :
  var archive = [...state.roundHistory];
  for (var i in archive) {
    if (archive[i]._id === action.roundId) {
      archive[i].tickets = action.data;
    }
  }
  return Object.assign({}, state, {
    roundHistory: archive
  });

How can it mutate the state if i use [...spread]?

回答1:

The [...state.roundHistory] here is similar to [].concat(state.roundHistory). It's creating a new array, but the objects in the array are shared with state.roundHistory. If you want to mutate them you'll need to make copies of each item.

You can do this using Object.assign, similar to how what you did for your return value:

var archive = state.roundHistory.map(value => Object.assign({}, value));

Or (as you suggested in your own answer), you can use object-spread notation:

var archive = state.roundHistory.map(value => {...value});


回答2:

Okay i got it. Spreading an array of objects gives a new array but with links to same objects. To avoid the mutation, i added this line: archive[i] = {...state.roundHistory[i]};

case 'ARCHIVE_TICKETS' :
  var archive = [...state.roundHistory];
  for (var i in archive) {
    archive[i] = {...state.roundHistory[i]};
    if (archive[i]._id === action.roundId) {
      archive[i].tickets = action.data;
    }
  }
  return Object.assign({}, state, {
    roundHistory: archive
  });