简体   繁体   English

我是否在减速器中改变了redux状态?

[英]Am I mutating the redux state in reducer?

I am trying to change one item in of an array in my state using a reducer. 我正在尝试使用reducer更改我的状态中的数组中的一个项目。

State looks like: 州看起来像:

state: {
  items: [
  {
    id: 1,
    name: 'Superman',
    wearsCape: true
  },
  {
    id: 2,
    name: 'Batman',
    wearsCape: true
  },
  {
    id: 3,
    name: 'Iron Man',
    wearsCape: false
  }
];
}

I am trying to filter through all the items in the state to search for first occurance of a superhero that has name equal sHero.name . 我试图过滤州内的所有项目,以搜索名称等于sHero.name的超级英雄的第一次sHero.name Then I am trying to change a property of found superhero. 然后我试图改变找到的超级英雄的属性。 The reducer code looks like: reducer代码如下:

function findCapedCrusader(state, { sHero }) {
  var result = state.items.filter(s => {
    return s.name === sHero.name;
  });

  result[0].wearsCape = false;

  return { ...state };

} }

Am I mutating the state by doing the above?? 我是通过上述做法改变国家吗?

NOTE: apologies for stupid example. 注意:为愚蠢的例子道歉。 I am new to react and redux. 我是新来的反应和减少。

The filter() method is returning a new array instance, so you are not mutating your state. filter()方法返回一个新的数组实例,因此您不会改变您的状态。 For more information, see the MDN documentation : 有关更多信息,请参阅MDN文档

Return value 返回值

A new array with each element being the result of the callback function. 一个新数组,每个元素都是回调函数的结果。

Yes you are mutating your state in this example. 是的,你在这个例子中改变你的状态。 While filter does produce a new array, it is really only a shallow copy of the original. 虽然filter确实产生了一个新的数组,但它实际上只是原始数据的浅层副本。 The elements of your state.items array are objects, so when you modify one in your new results array (which contains pointers to the original contents of state.items ) you modify the original object. state.items数组的元素是对象,因此当您在新results数组(包含指向state.items的原始内容的state.items )中修改一个state.items您将修改原始对象。 See this answer for a bit more on deep vs shallow copies: What is the difference between a shallow copy and a deep copy with JavaScript arrays? 有关深度和浅拷贝的更多信息,请参阅此答案: 浅拷贝和带有JavaScript数组的深拷贝之间有什么区别?

To fix this you can either: 要解决此问题,您可以:

1. Use the spread operator on result and then overwrite the value of wearsCape like this: 1.result上使用spread运算符,然后覆盖wearsCape的值,如下所示:

result = state.items.filter(s => s.name === sHero.name).map(s => {
    return {...s, wearsCape: false}
});

This method works with serializable and non-serializable data and is the recommended way to update nested state values. 此方法适用于可序列化和非可序列化的数据,是更新嵌套状态值的推荐方法。

Or 要么

2. Make a deep copy of state.items before filtering: 2.在过滤之前制作state.items的深层副本:

const results = JSON.parse(JSON.stringify(state.items)).filter(s => {
    return s.name === sHero.name;
});

This method is a bit strange but works well for serializable data in cases where the value you want to modify is deeply nested and using the spread operator ( ... ) many times would become cumbersome. 这种方法有点奇怪但适用于可序列化数据,如果要修改的值是深度嵌套的,并且多次使用扩展运算符( ... )会变得很麻烦。

You are. 你是。 Even though the filter function will produce a new array, the state is in the objects you return in that new array. 即使过滤器函数将生成一个新数组,状态也在您在该新数组中返回的对象中。 Based on that, you are changing the state, which does not comply which what a pure function is. 基于此,您正在改变状态,这不符合纯函数的含义。

Here I leave you with a good post that will help you to understand better what a deep copy is and how to accomplish it. 在这里,我给你留下了一篇很好的文章,它将帮助你更好地理解深层文本是什么以及如何完成它。

https://medium.com/@tkssharma/objects-in-javascript-object-assign-deep-copy-64106c9aefab https://medium.com/@tkssharma/objects-in-javascript-object-assign-deep-copy-64106c9aefab

As far as I know, filter method returns a new array but the returned elements still reference the old ones. 据我所知, filter方法返回一个新数组,但返回的元素仍然引用旧数组。 So, if someone mutates a property to the newly created array they also mutate the original one. 因此,如果某人将属性变为新创建的数组,他们也会改变原始数组。

 const state = { items: [ { id: 1, name: 'Superman', wearsCape: true }, { id: 2, name: 'Batman', wearsCape: true }, { id: 3, name: 'Iron Man', wearsCape: false } ] }; const newItem = state.items.filter( s => s.name === "Superman"); newItem[0].wearsCape = false; console.log( "newitem", newItem, "\\noriginal", state.items[0] ); 

If you want to change one object's property in the array and update your state: 如果要更改阵列中的一个对象属性并更新状态:

 const state = { items: [ { id: 1, name: 'Superman', wearsCape: true }, { id: 2, name: 'Batman', wearsCape: true }, { id: 3, name: 'Iron Man', wearsCape: false } ] }; const newItems = state.items.map( s => { if( s.name === "Superman") { return { ...s, wearsCape: false }; } return s; }); console.log( "new items", newItems, "original", state.items ); 

As you can see, the original items is not mutated. 如您所见,原始items未发生变异。 For your situation it will be something like that: 对于你的情况,它将是这样的:

function findCapedCrusader(state, { sHero }) {
  var newItems = state.items.map(s => {
    if (s.name === sHero.name ) {
        return { ...s, wearsCape = false }
    }
    return s;
  });
  return { ...state, items: newItems };
}

Again, this function will change one object's property and does not change anything else. 同样,此函数将更改一个对象的属性,并且不会更改任何其他内容。 I'm not quite sure this is what you want since you are trying a filter in your question. 我不太确定这是你想要的,因为你在问题中尝试filter If you want to update your state with one single object, I can suggest another solution. 如果您想用一个对象更新您的状态,我可以建议另一个解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM