Состояние Redux видоизменяется при слиянии lodash с - PullRequest
0 голосов
/ 04 декабря 2018

Я использую lodash mergeWith, чтобы объединить некоторые данные полезной нагрузки в часть моего избыточного состояния.Однако, делая это, я в конечном итоге непосредственно мутировал состояние.Я не понимаю, как это происходит, так как я использую {...state}, чтобы произошло слияние.Почему это происходит и что я могу сделать, чтобы не изменять свое состояние напрямую?Вы можете увидеть приведенный ниже фрагмент для примера того, что происходит.Спасибо!

const merger = (objectOne, objectTwo) => {
  const customizer = (firstValue, secondValue) => {
    return _.isArray(firstValue) ? secondValue : undefined;
  };

  return _.mergeWith(objectOne, objectTwo, customizer);
};

const state = {
  1: {a: true, b: true, c: true},
  2: {a: true, b: true, c: true},
  3: {a: true, b: true, c: true},
}

const payload = {
   2: {a: true, b: false, c: true},
}

console.log("Merged data:");
console.log(merger({...state}, payload));
console.log("Manipulated state:");
console.log(state);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вот в ореховой скорлупе вопрос:

let a = { foo: 'A'}
let c = { ... a }  // shallow copy of a

a.foo = 'boo'

console.log(a)
console.log(c) // works as expected c.foo is NOT changed and still is 'A'

Как видно из приведенного выше примера со свойствами расширения и значения на основе, мелкое копирование работает, как и ожидалось.Однако, когда вы делаете это:

let x = { foo: { boo: 'A' }}  // object as value this time
let y = { ... x }  // shallow copy of x

x.foo.boo = 'beer'

console.log(x.foo.boo)
console.log(y.foo.boo) // should be 'boo' but it is 'beer'

Мелкая копия также не работает, так как clone содержит ссылки, указывающие на старые x объекты вместо клонированных.

Для исправленияэто, а также, чтобы сделать ваш код несколько более кратким, вы можете:

const state = { 1: {a: true, b: true, c: true}, 2: {a: true, b: true, c: true}, 3: {a: true, b: true, c: true}, }
const payload = { 2: {a: true, b: false, c: true} }

const merger = (...args) => _.mergeWith(...args, (a,b) => _.isArray(a) ? b : undefined)

console.log("Merged data:");
console.log(merger(_.cloneDeep(state), payload));
console.log("Manipulated state:");
console.log(state);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Первый переключатель от lodash _.cloneDeep, который позволит глубоко скопировать все дерево объектов, а также вы можете сделать свой метод merge болеекраткий с ES6 spread и т. д.

0 голосов
/ 04 декабря 2018

Вы должны знать, что синтаксис распространения { ...state } делает только поверхностную копию вашего объекта.Таким образом, в действительности - глубоко вложенные свойства - в вашем конкретном случае { a: true, b: true, c: true } остаются теми же объектами по ссылке.Если вы хотите избежать ошибки изменения состояния, вы должны использовать, например, функцию cloneDeep из lodash.

merger(_.cloneDeep(state), payload);

...