在Redux Reducer中修改数组中特定项目的状态

时间:2019-12-25 23:56:24

标签: reactjs typescript redux react-redux state

我不能完全包住的样板。我查看了immutable modifying of state的常见模式,但问题是,所有这些模式都只是推向了最后,而不是针对特定的索引。

在进入实际代码之前,这是为了更好地想象(伪代码) 的状态状态结构

state = {
   quizMenu: {...},
   quizEditor: Array<Question>,

    > type Question = {
        id: number,
        question: string,
        questionOptions: Array<QuestionOption>,
      }

        > type QuestionOption = {
           id: number,
           optionText: string,
           isValid: boolean,
          }
}

enter image description here

希望这是有道理的。我创建了一个添加问题的操作,效果很好。现在,我试图创建一个操作来为现有问题添加选项,但是我无法将想法摆在嵌套对象数组中。

以下是我定义的相关行为的定义:

const AQO = 'ADD_QUESTION_OPTION';

/*
 * @param questionId - ID of the question we're accesssing in quizEditor array
 * @param id - id of the option we're adding (handled in component)
*/
const actionAddQuestionOption = createAction(
  AQO, 
  (questionId: number, id: number) => ({ 
    payload: {
      id,
      optionText: 'New option',
      isValid: false,
      questionId,
    },
  })
);

现在我的减速器是以下方式:

const reducer = createReducer({//...}, {
   [actionAddQuestionOption.type]: (state, action) => ({
     ...state,
     quizEditor: [...state.quizEditor][action.payload.questionId].questionOptions.push({
        id: action.payload.id,
        optionText: action.payload.optionText,
        isValid: action.payload.isValid,
     })
   })
}

这最终以这种怪物类型错误结束:https://pastebin.com/raw/pBbnxcQp

但是我很确定我在错误地访问对象数组中的数组。

quizEditor: [...state.quizEditor][action.payload.questionId].questionOptions

有人知道访问它的正确方法是什么?非常感谢!

2 个答案:

答案 0 :(得分:1)

push的{​​{1}}方法返回数组的新长度,而不是数组本身。您可以做的只是将新对象Array移到数组中,该对象又将返回带有新问题选项的新数组。

concat

此外,我们必须使用新数组在状态中仅修改该属性:

[...state.quizEditor][action.payload.questionId].questionOptions.concat({
        id: action.payload.id,
        optionText: action.payload.optionText,
        isValid: action.payload.isValid,
     })

感谢沉浸在redux工具箱中,我们可以使其更具可读性:

const reducer = createReducer({
  //...}, {
  [actionAddQuestionOption.type]: (state, action) => {
    const quizEditor = [...state.quizEditor];
    quizEditor[action.payload.questionId].questionOptions = quizEditor[
      action.payload.questionId
    ].questionOptions.concat({
      id: action.payload.id,
      optionText: action.payload.optionText,
      isValid: action.payload.isValid
    });

    return {
      ...state,
      quizEditor
    };
  }
});

答案 1 :(得分:1)

由于您使用的是内置redux-toolkitimmer,因此您可以直接更改状态并将其内部转换为不可变的更新

const reducer = createReducer({
  [actionAddQuestionOption.type]: (state, { payload: { questionId, ...option }}) => {
    const question = state.questionquizEditor(question => question.id === questionId)
    question.questionOptions.push(option)
  }
})

使其成为不可更改的更新的方式如下

const reducer = createReducer({
  [actionAddQuestionOption.type]: (state, { payload: { questionId, ...option } }) => ({
    ...state,
    quizEditor: state.quizEditor.map(question =>
      (question.id === questionId
        ? {
          ...question,
          questionOptions: [...question.questionOptions, option],
        }
        : question)),
  }),
})