У нас был следующий редуктор ngrx, но мы добавили вложенный объект в наше состояние (структура: settings: { a: boolean, b: string }
), поэтому мы решили использовать cloneDeep(obj)
от lodash вместо оператора распространения ...obj
, чтобы гарантировать неизменность нашего состояния, как указано во втором примечании в официальной документации. Раздел «Создание функции редуктора»:
Оператор распространения выполняет только поверхностное копирование и не обрабатывает глубоко вложенные объекты. Вам необходимо скопировать каждый уровень объекта, чтобы обеспечить неизменность. Существуют библиотеки, которые обрабатывают глубокое копирование, включая 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
, однако, является частью oldState
и поэтому передается cloneDeep()
lodash.
Есть идеи, почему изменение возвращенного состояния (т. е. использование _.deepClone(state)
вместо оператора спреда ...state
) имело бы такой эффект - и как это остановить?
Мы используем @ngrx/entity
, поэтому состояние расширяется EntityState<MyState>
. Я понимаю, что функции объекта библиотеки возвращают новое состояние (или " то же состояние, если не было внесено никаких изменений "), и что дополнительные свойства, такие как наш новый вложенный объект settings
, могут быть добавлены в состояние, но что
" [t] эти свойства должны быть обновлены вручную "- что я беру то есть я должен сам их клонировать.
Ошибка заключается в том, что мы пытаемся клонировать все состояние (которое расширяет EntityState<T>
), а не только дополнительные свойства?
Единственные изменения между рабочим и неработающим кодом были сделаны в методе reducer()
, поэтому я не думаю, что мы случайно запускаем какое-либо новое событие, которое не запускалось раньше, которое обычно связано с возникновением бесконечного цикла ...