繁体   English   中英

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

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

我正在尝试使用reducer更改我的状态中的数组中的一个项目。

州看起来像:

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

我试图过滤州内的所有项目,以搜索名称等于sHero.name的超级英雄的第一次sHero.name 然后我试图改变找到的超级英雄的属性。 reducer代码如下:

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

  result[0].wearsCape = false;

  return { ...state };

}

我是通过上述做法改变国家吗?

注意:为愚蠢的例子道歉。 我是新来的反应和减少。

filter()方法返回一个新的数组实例,因此您不会改变您的状态。 有关更多信息,请参阅MDN文档

返回值

一个新数组,每个元素都是回调函数的结果。

是的,你在这个例子中改变你的状态。 虽然filter确实产生了一个新的数组,但它实际上只是原始数据的浅层副本。 state.items数组的元素是对象,因此当您在新results数组(包含指向state.items的原始内容的state.items )中修改一个state.items您将修改原始对象。 有关深度和浅拷贝的更多信息,请参阅此答案: 浅拷贝和带有JavaScript数组的深拷贝之间有什么区别?

要解决此问题,您可以:

1.result上使用spread运算符,然后覆盖wearsCape的值,如下所示:

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

此方法适用于可序列化和非可序列化的数据,是更新嵌套状态值的推荐方法。

要么

2.在过滤之前制作state.items的深层副本:

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

这种方法有点奇怪但适用于可序列化数据,如果要修改的值是深度嵌套的,并且多次使用扩展运算符( ... )会变得很麻烦。

你是。 即使过滤器函数将生成一个新数组,状态也在您在该新数组中返回的对象中。 基于此,您正在改变状态,这不符合纯函数的含义。

在这里,我给你留下了一篇很好的文章,它将帮助你更好地理解深层文本是什么以及如何完成它。

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

据我所知, filter方法返回一个新数组,但返回的元素仍然引用旧数组。 因此,如果某人将属性变为新创建的数组,他们也会改变原始数组。

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

如果要更改阵列中的一个对象属性并更新状态:

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

如您所见,原始items未发生变异。 对于你的情况,它将是这样的:

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

同样,此函数将更改一个对象的属性,并且不会更改任何其他内容。 我不太确定这是你想要的,因为你在问题中尝试filter 如果您想用一个对象更新您的状态,我可以建议另一个解决方案。

暂无
暂无

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

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