React - redux状态突变错误

时间:2017-05-16 16:25:24

标签: javascript reactjs redux frontend mutation

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

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

   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是否会在调查中复制每个嵌套对象,如果我只是在调查对象的最顶层使用它,就像我在这里使用它一样?

3 个答案:

答案 0 :(得分:1)

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

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

您需要使用connect和mapStateToProps()从props访问您的调查状态。然后,您可以在reducer中使用object.assign逻辑来返回状态的新副本。

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

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

你的addNewSection()函数中根本不需要object.assign。只需创建新的部分变量,将其传递给您的动作创建者,您的动作创建者就会将其发送到您将使用object.assign的reducer,以返回将在您的this.props.survey上更新的新状态副本。 / p>

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

这里有关于使用mapStateToProps的提示: https://github.com/reactjs/react-redux/blob/master/docs/api.md

答案 1 :(得分:1)

首先,上述解决方案完全错误。 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 Object.assign({}, state, { userName: action.payload });

但是,在您的情况下,状态对象'调查'并不那么简单。它是深度嵌套的,Object.assign或者扩展运算符根本不能帮助防止突变。您有3个选择:

  1. 使用不可变JS库,它提供永远不会发生变异的地图和列表。
  2. 使用规范化库来平整您的状态。
  3. (一种不需要额外库的脏方法)使用以下解决方案修复变异。
  4. enter image description here

答案 2 :(得分:0)

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

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