如何在对象内部推送数组时避免突变

时间:2017-05-30 07:45:31

标签: redux react-redux immutability

我有一个公司和公司内部的对象,有一系列的团队。

  company: {
    teams: [
      {
        name: 'test team',
        description: 'dddd',
        team_manager: null,
        company: '592577d5b591966c8e535865',
        permalink: 'test-team',
        createdAt: '2017-05-30T07:38:58.983Z',
        updatedAt: '2017-05-30T07:38:58.983Z',
        id: '592d219277923054118e7299'
      }
    ],
    name: 'test company2',
    createdAt: '2017-05-24T12:08:53.418Z',
    updatedAt: '2017-05-24T12:08:53.419Z',
    id: '592577d5b591966c8e535865'
  }
}

添加团队后,我正在使用此缩减器将团队推送到阵列。

case types.ADD_TEAM_SUCCESS :
  return Object.assign({}, state, state.teams.push(action.newTeam));

这很好,但是,在控制台中我收到一条警告:

'错误:在调度中检测到状态突变,路径为:company.teams.0'

关闭对象并将新团队推送到阵列的正确方法是什么?

3 个答案:

答案 0 :(得分:3)

See this link

如果您使用的是es2015,我可以执行以下操作:

return Object.assign({}, state, { teams: [...state.teams, action.newTeam] });

您正在将对象直接推送到state.teams。您应该先复制并使用它。如果您不能使用spread运算符,则可以将state.teams切片为一个新变量,然后将其推送到该变量。

答案 1 :(得分:0)

问题在于Object.assign()没有对您的对象[1]进行深度克隆(请参阅"深度克隆警告")。

如果您的堆栈中没有任何实用程序库(如lodash),您可以使用JSON编码和解码来完成工作:

case types.ADD_TEAM_SUCCESS:
    let stateCopy = JSON.parse(JSON.stringify(state));
    state.teams.push(action.newTeam);
    return state;

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

答案 2 :(得分:0)

如前所述,Object.assign()不会对您的对象进行深层克隆。

我的建议是规范您的商店并分成两个商店公司和团队。

使用combineReducers并将其连接到一个商店,您将简化Reducer并使代码更具可读性。你也可以玩性能。

我的意思是......如果你的组件只是与公司合作而你将改变团队,你将避免轻易重新渲染。

检查Dan Abramov炉排视频教程 Redux: Normalizing the State Shape

我会以某种方式这样做(抱歉打字稿中的代码)

export interface ICompanyItem {    
    name: string;    
    id: string;
    createdAt: Date;
    updatedAt: Date;    
}

export interface ITeamItem {
    id: string;
    companyId: string
    name: string;
    description: string;
    team_manager: string;
    createdAt: Date;
    updatedAt: Date;
}

export interface ICompaniesState {
    items: { [id: string]: ICompanyItem };
}

export interface ITeamsState {
    items: { [id: string]: ITeamItem };
}


export const teamsReducer: Reducer<ITeamsState> = (state: ITeamsState, action: Action) => {

    if (isActionType(action, AddNewTeamItem)) {
        let itemsClone: { [id: string]: ITeamItem } = { ...state.items, [action.id]: action.team };

        return {
            ...state,
            items: itemsClone
        };
    }

    return state || unloadedState;
};