我们有以下 ngrx 减速器,但在我们的状态(结构:)中添加了一个嵌套对象settings: { a: boolean, b: string }
,因此决定使用 lodashcloneDeep(obj)
而不是...obj
扩展运算符来确保我们的状态是不可变的,根据官方文档“创建减速器功能”</a>部分:
扩展运算符只进行浅层复制,不处理深度嵌套的对象。您需要复制对象中的每个级别以确保不变性。有一些库可以处理深度复制,包括lodash和immer。
// 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
然而,它是 lodash 的一部分,oldState
因此传递给 lodash 的cloneDeep()
.
知道为什么更改返回的状态(即使用_.deepClone(state)
而不是扩展...state
运算符)会产生这种效果 - 以及如何阻止它?
我们正在使用@ngrx/entity
,所以状态正在扩展EntityState<MyState>
。我不理解库的实体函数返回一个新状态(或“如果没有进行任何更改,则返回相同的状态”),并且可以将其他属性(如我们的新嵌套settings
对象)添加到该状态,但
“[t]这些属性必须是手动更新”——我认为这意味着我必须自己克隆它们。
我们试图克隆整个状态(扩展EntityState<T>
)的错误,而不仅仅是附加属性?
工作代码和损坏代码之间的唯一更改是在reducer()
方法中进行的,所以我认为我们不会意外触发我们之前没有触发的任何新事件,这通常会导致无限循环......