【问题标题】:How to update single value inside array in redux如何在redux中更新数组内的单个值
【发布时间】:2018-08-07 08:23:18
【问题描述】:

我正在使用 reactredux 创建一个 todolist,当我更新 redux 状态数组时它不会重新渲染,我的状态实际上是一个包含对象的数组,如下所示:

[{index:1,value:'item1',done:false}, {index:2,value:'item2',done:false}]

我想要做的是点击我想将done的值切换为'true', 但不知何故,我无法做到这一点。

这就是我在减速器中所做的:

list.map((item)=>{
     if(item.index===index){
         item.done=!item.done;
         return [...state,list]
     }

但是即使 done 在单击切换按钮时不断变化,它也不会重新渲染。

似乎我正在以某种方式改变状态。 请告诉我我哪里出错了,我应该怎么做。

你能举出类似的例子吗?我可以正确更新简单数组的状态,但是为包含 objects 的数组执行此操作让我感到困惑。 那么,你能举个例子吗?

这是完整的 reducer 代码:

export default function todoApp(state=[],action){
    switch(action.type){
        case 'ADD_TODO':
            return [...state,action.item];
        case 'TOGGLE_TODOS':
            const index = action.index;
            const list = state;

            list.map((item)=>{
            if(item.index===index){
                item.done=!item.done;

            }
            return [...state,list];
            });
        default:
          return state;    
    } 
}

【问题讨论】:

    标签: reactjs redux state


    【解决方案1】:

    似乎我正在以某种方式改变状态。

    正确的你正在改变状态,因为在 js 中,变量总是得到对象/数组的引用。在您的情况下,item 将具有数组每个对象的引用,并且您直接改变了 item.done 的值。

    另一个问题是您没有正确返回最终对象,您还需要为每个地图迭代返回值,否则默认情况下它将返回 undefined

    这样写:

    case "TOGGLE_TODOS": 
        return list.map((item) => (
            item.index===index? {...item, done: !item.done}: item
        ))
    

    或者:

    case 'TOGGLE_TODOS':
        const index = action.index;
        const newState = [ ...state ];
        newState[index] = { ...state[index], done: !newState[index].done };
        return newState;
    

    完整代码:

    export default function todoApp(state=[], action){
        switch(action.type){
            case 'ADD_TODO':
                return [...state, action.item];
            case 'TOGGLE_TODOS':
                const index = action.index;
                return state.map((item) => (
                    item.index===index? {...item, done: !item.done}: item
                ))
            default:
                return state;    
        }
    }
    

    检查这个sn-p:

    let list = [
        {done:true, index:0},
        {done:false, index:1},
        {done: true, index:2}
      ]
    
    let index = 1;
    
    let newList = list.map(item => (
        item.index===index? {...item, done: !item.done}: item
    ))
    
    console.log('newList = ', newList);

    【讨论】:

    • 您能否举一个包含对象的数组示例。因为这让我很困惑。我只想更新对象的一个​​属性,我想知道怎么做。
    • @faraz 检查更新的答案,如果有任何疑问,请告诉我:)
    • 所以,在你上面的代码中。你会像这样返回状态 --> return {...obj,newObj} ??
    • 您在哪里感到困惑,您能否完整说明您尝试过的代码以及我将为您提供的帮助。
    • 更新了完整的 reducer 代码——我最初在做什么。它正在将 done 的值相应地更改为 true 和 false,但不会重新渲染。
    【解决方案2】:

    查看Array.prototype.Map 的文档。

    回调函数应该返回新数组的元素。试试这个:

    return list.map(item => {
      if (item.index === index) {
        return {
          done: !item.done
          ...item,
        }
    
      return item;
    });
    

    【讨论】:

    • 您能否举一个包含对象的数组示例。因为这让我很困惑。我只想更新对象的一个​​属性,我想知道该怎么做。
    【解决方案3】:

    虽然已经有两个正确答案了,但我也想在这里抛出lodash/fp,它更密集、更易读,也不会变异

    import { set } from 'lodash/fp'
    
    return list.map(item => {
        if (item.index === index) {
            return set('done', !item.done, item)
        }
        return item
    }
    

    【讨论】:

      猜你喜欢
      • 2016-06-08
      • 2021-03-06
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 2021-12-24
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多