为什么深度克隆我的状态会导致ngrx进入无限循环,不断调用我的reducer?

问题描述 投票:0回答:1

我们有下面的ngrx减速器,但是在我们的状态中添加了一个嵌套对象(structure: settings: { a: boolean, b: string }),所以决定使用lodash的 cloneDeep(obj) 而非 ...obj 传播操作符,以确保我们的状态是不可改变的,根据官方文档中的第二条说明。"创建还原器功能" 节。

展开运算符只做浅层复制,不处理深层嵌套的对象。你需要复制对象中的每一个层次,以确保不变性。有一些库可以处理深度复制,包括 宿雾沉浸.

// before:
export function reducer(state: MyState = initialState, action: Actions): MyState {
  switch (action.type) {
    // ...
    case MY_TASK: {
      return {
        ...state,
        prop1: action.payload.prop,
        prop2: initialState.anotherProp
      };
    }
    // ..
  }
}

当我们把它改成下面的样子时,ngrx一直在调用 reducer() 方法,有效地阻止(崩溃)了浏览器。

// after - causes infinite loop
import * as _ from 'lodash';
// ..

export function reducer(oldState: MyState = initialState, action: Actions): MyState {
  function nextState(stateChanges?: (MyState) => void): MyState {
    const draftState: MyState = _.cloneDeep(oldState);
    if (stateChanges) {
      stateChanges(draftState);
    }
    return draftState;
  }

  switch (action.type) {
    // ...
    case MY_TASK: {
      return nextState(s => {
        s.prop1 = action.payload.prop;
        s.prop2 = initialState.anotherProp;
      });
    }
    // ..
  }
}

stateChange甚至不接触新的嵌套的 附加状态 (即 settings 对象),只有平面的(prop1, prop2)我们之前的。settings 然而,是属于 oldState 于是就传到了罗达什的 cloneDeep().

知道为什么要改变返回状态吗? (即使用 _.deepClone(state) 而不是铺开 ...state 操作者) 会有这样的效果--如何阻止它?

我们正在使用 @ngrx/entity,所以状态在延伸 EntityState<MyState>. 我不明白 库的实体functinos返回一个新的状态。 (或 "如果不做任何改变,则为同样的状态"),并且, 附加属性 像我们新的嵌套式 settings 对象可以添加到状态中,但 "这些属性必须手动更新"--我认为这意味着我必须自己克隆它们。

是否我们试图克隆整个状态(它扩展了 EntityState<T>),而不仅仅是 附加属性?

工作代码和坏掉的代码之间的唯一变化是在 reducer() 方法,所以我不认为我们不小心触发了任何我们之前没有触发的新事件,这通常会导致一个无限循环......。

lodash infinite-loop ngrx ngrx-store ngrx-entity
1个回答
0
投票

_.cloneDeep 是最坏的情况 ngrx 因为这意味着所有的东西都已经在商店里被触动过了,它再次触发了所有的选择器。

从描述的错误中,我可以假设你有一个 selector 导致 dispatch 在某些情况下,由于被派遣的 action 造成 _.cloneDeep 选择器再次被触发,导致 dispatch 等...

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.