【问题标题】:How to mutate a array on state in a redux reducer?如何在redux reducer中改变状态数组?
【发布时间】:2019-02-03 14:25:25
【问题描述】:

更改前的状态如下所示:

foreignBases: [
  {
    base: {
      id: "5b8125ec14bb4f35f8f01aa9",
      ...
    },
    baseuser: {
      userId: "tester1",
      ...
    }
  },
  { base: { ... }, baseuser: { ... } }
]

通过调度,用户将baseuser 键中的布尔值更改为true,然后reducer 应该更新此特定键值对的状态,但我似乎无法正确处理:

for (let i = 0; i < state.foreignBases.length; i++) {
  if (action.baseUser.created === state.foreignBases[i].baseuser.created) {
    return Object.assign({}, state, {
      foreignBases: [
        ...state.foreignBases,
        {
          base: { ...state.foreignBases[i].base },
          baseuser: action.baseUser
        }
      ]
    });
}

这只是将另一个对象添加到状态中,而我真的只需要在一个对象中替换一个 baseuser 的布尔值

【问题讨论】:

  • 您介意发布您的操作吗?

标签: javascript reactjs redux state reducers


【解决方案1】:

请务必在下方查看更新。

扩展运算符正在重新插入整个foreignBases,然后您添加另一个对象,我认为这是您的预期突变。

我认为你的意思是这样的(未经测试)

for (let i = 0; i < state.foreignBases.length; i++) {
  if (action.baseUser.created === state.foreignBases[i].baseuser.created) {
    let foreignBases = [...state.foreignBases];
    foreignBases[i].baseuser = action.baseUser;
    return Object.assign({}, state, {foreignBases});
  }
}

更新:@devserkan 提醒我扩展运算符“不做深拷贝”,这在 Redux 中是一个禁忌!所以我去找the updating an item in an array official pattern,我相信它是这样应用的(同样,未经测试):

let foreignBases = state.foreignBases.map((foreignBase) => {
  if (action.baseUser.created === foreignBase.baseuser.created) {
    return {action.baseUser};
  } else {
    return foreignBase
  }
});
return Object.assign({}, state,  { 
   ...foreignBase,
   baseuser: action.baseUser
});

更新 2:cmets 中的@devserkan 再次提供了宝贵的见解,这次通过嵌套在状态对象的部分中来修复原始 for 循环。这类似于突变。这种方法避免了这种情况,并允许您仍然使用 for 循环。

for (let i = 0; i < state.foreignBases.length; i++) {
  if (action.baseUser.created === state.foreignBases[i].baseuser.created) {
    const newItem = {
      ...state.foreignBases[i],
      baseuser: action.baseUser
    };
    const newforeignBases = Object.assign([], state.foreignBases, {
      [i]: newItem
    });
    return Object.assign({}, state, { foreignBases: newforeignBases });
  }
}

【讨论】:

  • 太棒了,就像一个魅力。谢谢你。你能解释一下为什么这有效吗?这背后你的思考过程是什么?
  • 只是一个提醒。传播语法不做深拷贝。因此,当您更改复制对象的属性时,原始对象也会发生变异。
  • @Helle 新模式是否有助于使这更有意义?我的想法基本上是在进行对象分配之前创建 foreignBases 对象。你已经找到了正确的foreignBase,只需要在添加到state之前稍微修改一下,当然,你不能直接修改state。
  • 我打算提供这样的答案。 map 是这里的工具。没有 for 循环,没有直接改变状态。但是,这里有两个问题:) return {action.baseUser}; 这不起作用,因为语法错误。 return {baseuser: action.baseUser}; 是正确的。但是这次我们在项目中丢失了base。所以:return { ...foreignBase, baseuser: action.baseUser }; 顺便说一句很好的解决方案。
  • 新模式与@devserkan 的最新return 评论相结合,使其工作。为了向我自己重申解决方案,我们不能从我的解决方案开始,因为它会直接改变状态。相比之下,你们两个人的解决方案一起不会直接改变状态,而是映射一个新的作为副本,然后成为状态
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 2020-04-16
  • 1970-01-01
相关资源
最近更新 更多