发生Redux状态更改时,组件不会更新 [英] Component won't update when a redux state change occurs

查看:46
本文介绍了发生Redux状态更改时,组件不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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;
}

这是代码. 问题是当属性数量增加时,redux认为状态没有变化,因此mapStateToProps无法运行. 请问有什么解决办法吗?

Here is the code. Problem is when the properties quantity increase, redux think the state has no change so mapStateToProps not run. Is there any solution for this please?

推荐答案

Array

Array filter returns a new array, it does not update the original. Return directly or save to a variable to make changes

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

However, this is not doing what you think it is. You should use map instead

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

filter 仅当回调函数返回true时,才从数组返回值.您的函数不会检查是否应过滤,而是尝试修改值(并且是).

filter will only return values from the array if the callback function returns true. Your function isn't checking if it should filter, its trying to modify values (and is).

map 将为数组的每个索引返回回调的值.因此,如果您如上所示在最后返回每个项目,则给定的回调应该执行预期的操作.

map will return the value of the callback for each index of the array. So your given callback should do what you expect if you return each item at the end as shown above.

最后一个问题是确保您不改变状态. 这很可能是导致问题的根源.

The last piece of the problem is to ensure you don't mutate state. This is most likely the root your problem.

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

使用mapfilter,您将创建一个新的状态数组. 但是,在执行item.quantity++;时,您正在同时嵌套状态为原始状态和新状态的嵌套对象,因为嵌套对象仍使用相同的引用.在映射时创建新对象不仅可以确保主状态数组是新的,而且还可以确保任何嵌套对象(此特定示例仅保护1个深度对象).

With map and filter, you are creating a new state array. But, when doing item.quantity++;, you are mutating a nested object in both the original state and new state, as the nested objects are still using the same references. Creating a new object while mapping ensures that not only the main state array is new, but also any nested objects as well (this specific example only protects 1 deep).

它比答案更长,但我想弄清楚.

您遇到的问题是一个非常普遍的问题,与JavaScript处理非原始数据类型的方式有关.当您创建数组或对象并将其分配给变量时,该变量实际上并不包含该对象,它包含对该对象的引用或指针.对象本身实际上存储在内存中的其他位置.

The problem you're having is a very common one, and has to do with how JavaScript handles non-primitive data types. When you create an array or object and assign it to a variable, the variable doesn't actually contain the object, it contains a reference or a pointer to the object. The object itself is actually stored somewhere else in memory.

为清楚起见,让我们仅用<>包围的数字来表示参考. 让我们创建一个对象:

For clarity, lets just denote references by numbers surrounded by <>. Lets create an object:

let obj1 = {a: 'b'};

obj1保存对我们创建的新对象的引用,可以说引用为< 1>.现在让我们复制对象.

obj1 holds the reference to the new object we created, lets say the reference is <1>. Now lets make a copy of the object.

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

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

由于变量包含引用,因此实际分配obj2的是与< 1>的引用相同.

Since the variable holds a reference, what were actually assigning obj2 is the same reference of <1>.

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

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

误解之所以出现在这里,是因为人们认为obj2现在是其自己的原始副本.但是正如您所看到的,它们引用内存中的同一对象.结果是,现在执行obj2.a = 'c'之类的操作会导致obj1.a也等于'c'.

So the misconception comes in here because people assume that obj2 is now its own independent copy of the original. But as you see, they reference the same object in memory. The result is that doing something like obj2.a = 'c' now causes obj1.a to also equal 'c'.

运行下面的代码片段以供自己查看:

Run the snippet below to see for yourself:

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

obj2.a = 'c';

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

我们如何避免制作误导性副本?

最简单的方法是创建一个全新的对象,并使用

The simplest way is to create a brand new object and just fill it with the old object's values by using spread syntax.

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);

现在您可以看到我们已经复制了一个对象,但是每个对象都在内存中引用了它们自己的对象.这几乎总是我们想要的行为.

Now you can see that we have copied an object, but each reference their own objects in memory. This is almost always our desired behavior.

当我们引入嵌套时,事情变得更加混乱.但是,如果您了解基本概念,它应该更有意义.

Things get extra confusing when we bring in nesting. But if you understand the basic idea it should make more sense.

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

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

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

嵌套对象也获得自己的引用.因此,当我们分解以创建新对象时,这就是我们正在做的事情.

Nested objects get their own references too. So when we destructure to create a new object here's what we're doing.

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引用了内存中的新位置,但是嵌套对象仍然具有与以前相同的引用!

obj2 references a new place in memory, but the nested object still has the same reference as before!

因此,即使我们在顶部创建了一个新对象,如果我们修改嵌套属性,我们的行为也会与以前类似.这被称为浅拷贝".试试看:

So if we modify a nested property we have a similar behavior as before even though we made a new object at the top. This is called a "shallow copy". Try it out:

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

let obj2 = {...obj1};

obj2.nested.a = 'c';

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

解决方案:也创建具有所有嵌套值的新对象.

Solution: make new objects of all nested values as well.

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

现在,我们已经成功创建了嵌套对象的完全独立副本.

Now we have successfully created an completely independent copy of a nested object.

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及其嵌套值将保持不变.

You may edit obj2 and its nested values with confidence that obj1 and it's nested values will remain unchanged.

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

obj2.nested.a = 'c';

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

这篇关于发生Redux状态更改时,组件不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆