无法弄清楚如何在不引起突变的情况下更改减速器中的状态

Can't figure out how to change State in reducer without causing a mutation

尝试更新我的 reducer 中的状态后,我不断收到以下错误:

"Error: A state mutation was detected inside a dispatch, in the path: quiz.questions.0.answer. Take a look at the reducer(s) handling the ac..."

我很确定我没有改变原始状态,因为我正在使用 object.assign 但错误仍然存​​在。

我的减速器:

    case types.UPDATE_QUIZ_ANSWER:
        let newStateObject =  Object.assign({}, state);
        let currentQuestion = newStateObject.questions.find(x => x.id == parseInt(action.data.questionId));
        currentQuestion.answer = action.data.answer;
        return Object.assign({}, newStateObject); 

我的状态对象:

{"questions":
    [{"id":1,"questionText":"Camps is?","multipleChoiceOption1":
     {"value":"1","label":"Great"},"multipleChoiceOption2":
     {"value":"2","label":"Fun"},"multipleChoiceOption3":
     {"value":"3","label":"Awesome"},"multipleChoiceOption4":
     {"value":"4","label":"All of the above"},
     "answer":"2"},
     {"id":2,"questionText":"At Camps we will?","multipleChoiceOption1":
     {"value":"1","label":"AAA"},"multipleChoiceOption2":
     {"value":"2","label":"Adult Focused"},"multipleChoiceOption3":
     {"value":"3","label":"CCC"},"multipleChoiceOption4":
     {"value":"4","label":"All of the above"},
      "answer":"3"}],
  "results":
     {"quizPass":false,"quizResults":[]}}"

此代码正在改变您的状态:

let currentQuestion = newStateObject.questions.find(x => x.id ==
    parseInt(action.data.questionId));
currentQuestion.answer = action.data.answer;

Object.assign 没有深度克隆所以,而你的 newStateObject 肯定和你原来的 state 不一样,你从数组中拉取的 currentQuestion questions 与原始状态对象图中相同。

您可能想查看类似 Immutable.js 的内容,但请这样想:您要更改的实际对象需要替换,其父对象(object/array引用它)等等,直到您所在州的顶部。如果您使用的是 combineReducers,您只需担心 切片 的顶部,因为 combineReducers 会在上面完成工作。

展开运算符 ... 又名 Object.assign 仅适用于对象属性的第一级。

let newStateObject =  Object.assign({}, state);
let currentQuestion = newStateObject.questions.find(x => x.id == parseInt(action.data.questionId));
currentQuestion.answer = <----- here is the mutation

您可以做的是在每个级别创建对象的副本:

// make a copy of the array
let newQuestions = [...newStateObject.questions];
let questionIndex = newQuestions.findIndex(x => x.id == parseInt(action.data.questionId));
// update array and question
newQuestions[questionIndex] = {...newQuestions[questionIndex], answer: action.data.answer};
// return new result
return  {...state, questions: newQuestions};