ngrx-默认值是否通过扩展运算符覆盖?

时间:2018-04-30 15:00:18

标签: javascript angular immutability ngrx-store

我正在研究一个ngrx选择器,它将状态树的一部分转换为视图模型。举个简单的例子,在我的状态树中,我有一个manager数组。因此,我对状态树进行了以下设置,并查看了模型 -

export interface Manager {
    id: string,
    name: string
}

export interface AppState {
    managers: Manager[]
}

export interface ManagersVM {
    byId: {[key: string]: Manager},
    allIds: string[]
}

export const defaultManagersVM: ManagersVM {
    byId: {},
    allIds: []
};

然后在我的选择器中,我有:

export const selectManagersVM = createSelector(selectManagers, (data) => {
    let mgrsVM: ManagersVM = { ...defaultManagersVM };
    for(let mgr of data.managers) {
        mgrsVM.byId[mgr.id] = mgr;
        mgrsVM.allIds.push(mgr.id);
    }
})

我遇到的问题是:

let mgrsVM: ManagersVM = { ...defaultManagersVM };

似乎没有制作defaultManagersVMs属性的副本。 (运行选择器后,一个console.log的defaultManagersVM显示它现在有一个非空的byId和allIds)。我的印象是新定义的对象中的传播操作符会创建一个副本,但这看起来是错误的。如何确保defaultManagersVM不会在我的选择器中发生变异。

2 个答案:

答案 0 :(得分:1)

扩展运算符does not make a deep copy of nested objects,JavaScript默认没有此功能。一个选项是使用外部库(即Lodash,它支持深度克隆)。

或者,如果您需要一些其他库未涵盖的特定功能,您可以编写自己的递归深度克隆功能。

答案 1 :(得分:0)

这是一个递归的 deepClone 方法,我选择了某个似乎可以完成工作的方法

export function deepClone(state) {

  if (Array.isArray(state)) {
    const newState = [];
    for (let index = 0; index < state.length; index++) {
      const element = state[index];
      newState[index] = deepClone(element);
    }
    return newState;
  }
  if (typeof state === 'object') {
    const newState = {...state};
    Object.keys(newState).forEach(key => {
      if (newState.hasOwnProperty(key)) {
        const val = newState[key];
        newState[key] = deepClone(val);
      }
    });
    return newState;
  }

  return state;
}

您可能还想将 deepFreeze 应用于任何不应变异的内容。你得到一个错误,但至少它是在突变点。

export function deepFreeze (o) {
  Object.freeze(o);

  Object.getOwnPropertyNames(o).forEach((prop) => {
    if (o.hasOwnProperty(prop)
    && o[prop] !== null
    && (typeof o[prop] === 'object')
    && !Object.isFrozen(o[prop])) {
      deepFreeze(o[prop]);
    }
  });

  return o;
}