Компонент не будет обновляться при изменении состояния избыточности - PullRequest
0 голосов
/ 14 января 2020
case 'ADD_TO_CART': {
    let item = action.payload;
    let newState = addToCart(state, item);
    return newState;
}
const increaseItem = (array = [], dish) => {
    array.filter((item) => {
        if (item.id === dish.id) {
            item.quantity++;
        }
    });
    return array;
}

case 'INCREASE_ITEM': {
    let item = action.payload;
    console.log('run in increase')
    let newState = increaseItem(state, item);
    return newState;
}

Вот код. Проблема заключается в том, что при увеличении количества свойств избыточность думает, что состояние не меняется, поэтому mapStateToProps не запускается Есть ли какое-нибудь решение для этого, пожалуйста?

1 Ответ

2 голосов
/ 14 января 2020

Array filter возвращает новый массив, но не обновляет исходный. Вернитесь напрямую или сохраните переменную, чтобы внести изменения

const increaseItem = (array = [], dish) => {
    return array.filter(//your code here);
    //return array;
}

// OR

const increaseItem = (array = [], dish) => {
    const newArray = array.filter(//your code here);
    return newArray;
}

Однако , это не делает то, что вы думаете. Вы должны использовать map вместо

const increaseItem = (array = [], dish) => {
    return array.map((item) => {
        if (item.id === dish.id) {
            item.quantity++;
        }
        return item; // Add this
    });
}

filter будет только возвращать значения из массива, если функция обратного вызова возвращает true. Ваша функция не проверяет, должна ли она фильтровать, она пытается изменить значения (и есть).

map вернет значение обратного вызова для каждого индекса массива. Таким образом, ваш обратный вызов должен делать то, что вы ожидаете, если вы возвращаете каждый элемент в конце, как показано выше.

Последний кусок проблемы - убедиться, что вы не изменили состояние. Скорее всего, это root ваша проблема .

const increaseItem = (array = [], dish) => {
    return array.map((item) => {
      let item = {...item}; // Add this
        if (item.id === dish.id) {
            item.quantity++;
        }
        return item;
    });
}

С map и filter вы создаете новый массив состояний. Но , когда вы делаете item.quantity++;, вы изменяете вложенный объект как в исходном, так и в новом состоянии, поскольку вложенные объекты все еще используют одни и те же ссылки. Создание нового объекта при отображении гарантирует, что не только основной массив состояний является новым, но также и любые вложенные объекты (этот конкретный c пример защищает только 1 глубину).

Объяснение

Это длиннее, чем ответ, но я хотел прояснить.

Проблема, с которой вы столкнулись, очень распространенная и связана с тем, как JavaScript обрабатывает не примитивные типы данных. Когда вы создаете массив или объект и присваиваете его переменной, переменная фактически не содержит объект, она содержит ссылку или указатель на объект. Сам объект фактически хранится где-то еще в памяти.

Для ясности, давайте просто обозначим ссылки числами, окруженными <>. Давайте создадим объект:

let obj1 = {a: 'b'};

obj1 содержит ссылку на новый объект, который мы создали, допустим, ссылка - <1>. Теперь давайте сделаем копию объекта.

let obj1 = {a: 'b'};
let obj2 = obj1;

console.log(obj1);
console.log(obj2);

Поскольку переменная содержит ссылку, то, что на самом деле присваивало obj2, является той же ссылкой <1>.

obj1 
// reference: <1>
// value: {a: 'b'}

obj2
// reference: <1>
// value: {a: 'b'}

Таким образом, неправильное представление приходит сюда, потому что люди предполагают, что obj2 теперь является его собственной независимой копией оригинала. Но, как вы видите, они ссылаются на один и тот же объект в памяти. В результате, если сделать что-то вроде obj2.a = 'c', то obj1.a также станет равным 'c'.

Запустите фрагмент ниже, чтобы убедиться в этом:

let obj1 = {a: 'b'};
let obj2 = obj1;

obj2.a = 'c';

console.log(obj1);
console.log(obj2);

Как избежать создания вводящих в заблуждение копий?

Самый простой способ - создать новый объект и просто заполнить его значения старого объекта путем разрушения .

let obj1 = {a: 'b'};
let obj2 = {...obj1};

// obj1 
// reference: <1>
// value: {a: 'b'}

// obj2
// reference: <2>
// value: {a: 'b'}

obj2.a = 'c';

console.log(obj1);
console.log(obj2);

Теперь вы можете видеть, что мы скопировали объект, но каждый ссылается на свой объект в памяти. Это почти всегда наше желаемое поведение.

Вещи становятся еще более запутанными, когда мы вводим вложения. Но если вы понимаете основную идею c, это должно иметь больше смысла.

let obj1 = {
  foo: 'bar',
  nested: {a: 'b'}
};

// obj1 
// reference: <1>
// value: {foo: 'bar', nested: <2>}

// nested
// reference: <2>
// value: {a: 'b'}

Вложенные объекты также получают свои собственные ссылки. Поэтому, когда мы деструктурируем, чтобы создать новый объект, вот что мы делаем.

let obj2 = {...obj1};

obj1 
// reference: <1>
// value: {foo: 'bar', nested: <2>}

nested
// reference: <2>
// value: {a: 'b'}

obj2
// reference: <3>
// value: {foo: 'bar', nested: <2>}

obj2 ссылается на новое место в памяти, но вложенный объект по-прежнему имеет ту же ссылку, что и раньше!

Таким образом, если мы изменяем вложенное свойство, мы ведем себя так же, как и раньше, даже если мы создали новый объект сверху. Это называется «мелкой копией». Попробуйте:

let obj1 = {
  foo: 'bar',
  nested: {a: 'b'}
};

let obj2 = {...obj1};

obj2.nested.a = 'c';

console.log(obj1);
console.log(obj2);

Решение : также создавать новые объекты со всеми вложенными значениями.

let obj2 = {...obj1, nested: {...obj1.nested}};

Теперь мы успешно создали полностью независимую копию вложенного объекта.

obj1 
// reference: <1>
// value: {foo: 'bar', nested: <2>}

nested
// reference: <2>
// value: {a: 'b'}

obj2
// reference: <3>
// value: {foo: 'bar', nested: <4>}

nested
// reference: <4>
// value: {a: 'b'}

Вы можете редактировать obj2 и его вложенные значения с уверенностью, что obj1 и его вложенные значения останутся без изменений.

let obj1 = {foo: 'bar', nested: {a: 'b'}};
let obj2 = {...obj1, nested: {...obj1.nested}};

obj2.nested.a = 'c';

console.log(obj1);
console.log(obj2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...