Redux状态变异

时间:2016-07-23 00:30:38

标签: reactjs redux react-router react-redux

为什么当我正在传递一个新对象时,反应会认为我正在改变状态?我错过了什么吗? 这是我的减速器,用于在测验数组中的测验对象上添加问题。

case types.UPDATE_QUESTION_SUCCESS: {
  let quizContext = state.filter(quiz => quiz.id === action.quizId);
  let filteredQuestions = quizContext[0].questions.filter(question => 
    question.questionId !== action.question.questionId
  );
  filteredQuestions.push(action.question);
  quizContext[0].questions = filteredQuestions;
  let quiz = quizContext[0];
  return [...state.filter(quiz => quiz.id !== action.quizId), Object.assign({}, quiz)];
}

错误:

Invariant Violation: A state mutation was detected between dispatches, in the path `quizes.4.questions.1`. This may cause incorrect behavior. (http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)

2 个答案:

答案 0 :(得分:2)

首先,由于您只关心quizContext[0]filter有点矫枉过正。 只是做:

const quiz = state.find(quiz => quiz.id === action.quizId);

获得相同的结果。

我不想在这里做太多的代码审查,但还有一件事。即使您应始终使用let,也要使用constconst只是意味着你无法重新分配你仍然可以改变它的变量。

然后你过滤问题添加一个,然后将其添加回刚刚找到的测验。

quizContext[0].questions =是个问题,因为即使您的对象现在处于一个新数组中,它们仍然是相同的对象,所以如果你改变它们就会改变状态。

const quiz = Object.assign({}, state.find(quiz => quiz.id === action.quizId));

所以改写完整的东西,你最终得到这样的东西:

case types.UPDATE_QUESTION_SUCCESS:
{
  const quiz = Object.assign({}, state.find(quiz => quiz.id === action.quizId));
  quiz.questions = quiz.questions.filter(question =>
    question.questionId !== action.question.questionId
  );
  quiz.questions.push(action.question);
  return [...state.filter(quiz => quiz.id !== action.quizId), quiz];
}

但请记住,大多数情况下,您根本不想过滤减速机中的数据。相反,我建议您使用reselect,以便您可以根据商店中的数据计算衍生数据。

答案 1 :(得分:0)

您正在根据减速器改变状态。当您使用过滤器函数时,传递给过滤器的对象是原始对象的引用,您不在此处执行deepCopy。这一行filterQuestions.push(action.question)实际上正在改变状态。

试试这个: let quizContext = cloneDeep(state.filter(quiz => quiz.id === action.quizId));

虽然可能有一个更优雅的解决方案,但这是你出错的地方。返回的过滤对象是对原始数组的引用,但不是新对象。所以你最终改变了状态中的原始对象。

- 更多澄清 -

cloneDeep是一个lodash函数,如果你使用Object.assign,它只会进行浅合并,而不是深度合并。因此,当状态在更深层次上发生变异时,通过改变原始状态,引用仍然是原始对象

- 编辑2 -

正如mash所说,改变你的状态的行是quizContext[0].questions = filteredQuestions;并使用Object.assign如果你确定没有嵌套状态,在这种情况下会有更多的reducers