React - redux 状态突变错误

React - redux state mutation error

我正在尝试向调查对象添加一个部分及其抛出状态突变错误。

这是我调用将整个调查对象作为参数的动作创建器的方法。

   addNewSection(sectionName){
   const id = performance.now();
    let newSurvey = Object.assign({}, this.state.survey);
    const section = Object.assign({},{
        "type": "section",
        "id": id,
        "title": sectionName,
        "position": {
            "offset": 0,
            "width": 12,
            "order": 1
        },
        "items": []
    });
    newSurvey.layout.sections.push(section);
    this.setState({survey: newSurvey});
    this.props.actions.updateSurvey(newSurvey);
}

动作创作者:

export function updateSurvey(survey){
return {type:types.ADD_SECTION_SUCCESS, survey};
}

减速器:

export default function surveyReducer(state = initialState.survey, action){
switch(action.type){

    case types.ADD_SECTION_SUCCESS:
        return action.survey;

    default:
         return state
    }    
}

状态对象的形式为:

survey: {
layout: {
    sections: [{},{},{}]
    },
    questions:[{},{},{}]
}

我一定是误会了Object.assign。 Object.assign 是否会复制调查中的每个嵌套对象,如果我只是在调查对象的最顶层使用它,就像我在这里使用的那样?

您可以使用扩展运算符以 ES6 方式克隆对象:

let newSurvey = {...this.state.survey}

您似乎对应该在何处更改状态感到困惑。看起来您在 addNewSection 函数中根本没有使用 redux 状态。您只是在更新本地组件状态。你甚至不需要在这里使用 object.assign 你可以更新本地状态并随意改变它。

当您 return 将新调查作为调查状态时,您会改变减速器中的状态。

您需要使用 connect 和 mapStateToProps() 从道具访问您的调查状态。然后,您可以在减速器中使用 object.assign 逻辑来 return 状态的新副本。

function mapStateToProps(state) {
  return { survey: state.survey }
}

您可以从 this.props.survey 访问调查并将其显示在您想要的位置。

您的 addNewSection() 函数中根本不需要 object.assign。只需创建您的新部分变量,将其传递给您的动作创建者,您的动作创建者会将其分派给您的减速器,您将使用 object.assign 到 return 状态的新副本,该副本将在您的 this.props.survey.

此外,建议在 object.assign 上使用对象扩展语法以获得更好的语法,请参见此处:http://redux.js.org/docs/recipes/UsingObjectSpreadOperator.html

此处提供有关使用 mapStateToProps 的提示: https://github.com/reactjs/react-redux/blob/master/docs/api.md

首先,上面提到的解决方案是完全错误的。 Object.assign 和 ES6 传播运算符永远不会处理像您这样的深层嵌套数据结构。它们不会阻止任何状态突变。

其次,状态突变错误总是与 REDUX 的状态相关,而不是本地状态。

export default function headerReducer(state = {userName: ''}, action) {
    switch (action.type) {
        case 'SSO_USER_ACTION':
        {
            return Object.assign({}, state, { userName: action.payload });
        }
        default:
            return state;
    }
}

查看上面的示例减速器。这里我们总是return一个新的对象,使用:

return Object.assign({}, state, { userName: action.payload });

但是,在您的情况下,状态对象 'survey' 并不是那么简单。它嵌套很深, Object.assign OR 展开运算符根本无法防止突变。您有 3 个选项:

  1. 使用不可变的 JS 库,它提供永远不会被改变的映射和列表。
  2. 使用规范化库来扁平化你的状态。
  3. (一种不需要额外库的肮脏方法)使用以下解决方案修复突变。