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

查看:90
本文介绍了当 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 filter 返回一个新数组,它不会更新原始数组.直接返回或保存到变量中进行更改

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天全站免登陆