更新项目数组中的单个值反应还原

时间:2016-12-07 13:20:45

标签: javascript reactjs redux state reducers

我有一个待办事项列表,如果用户点击“完成”,我想将数组中该项目的状态设置为“完成”。

这是我的行动:

export function completeTodo(id) {
    return {
        type: "COMPLETE_TASK",
        completed: true,
        id
    }
}

这是我的减速机:

case "COMPLETE_TASK": {
             return {...state,
                todos: [{
                    completed: action.completed
                }]
             }
        }

我遇到的问题是新状态不再具有与所选项目上的待办事项关联的文本,并且ID不再存在。这是因为我覆盖了州并忽略了之前的属性吗?我的对象项onload看起来像这样:

Objecttodos: Array[1]
    0: Object
        completed: false
        id: 0
        text: "Initial todo"
    __proto__: Object
    length: 1
    __proto__: Array[0]
    __proto__: Object

如您所见,我想要做的就是将完成的值设置为true。

3 个答案:

答案 0 :(得分:41)

您需要转换todos数组以更新相应的项目。 Array.map是最简单的方法:

case "COMPLETE_TASK":
    return {
        ...state,
        todos: state.todos.map(todo => todo.id === action.id ?
            // transform the one with a matching id
            { ...todo, completed: action.completed } : 
            // otherwise return original todo
            todo
        ) 
    };

有一些库可以帮助您进行这种深度状态更新。您可以在此处找到此类库的列表:https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities

就个人而言,我使用ImmutableJS(https://facebook.github.io/immutable-js/)解决了updateInsetIn方法的问题(对于有大量键的大对象,它比普通对象和数组更有效)对于数组,但对于小数组则较慢。)

答案 1 :(得分:3)

  

新状态不再具有与该待办事项关联的文本   所选项目和ID不再存在,这是因为我   覆盖状态并忽略以前的属性?

是的,因为在每次更新期间,您都要使用仅一个completed分配一个新数组,并且该数组不包含任何先前的值。因此更新后的数组将没有以前的数据。这就是为什么更新后文本和ID不存在的原因。

<强>解决方案:

1 - 使用array.map查找正确的元素,然后更新值,如下所示:

case "COMPLETE_TASK":
    return {
        ...state,
        todos: state.todos.map(todo => 
            todo.id === action.id ? { ...todo, completed: action.completed } : todo
        ) 
    };

2-使用array.findIndex查找该特定对象的索引然后更新它,如下所示:

case "COMPLETE_TASK":
    let index = state.todos.findIndex(todo => todo.id === action.id);
    let todos = [...state.todos];
    todos[index] = {...todos[index], completed: action.completed};
    return {...state, todos}

检查此片段,您将更好地了解您正在做的错误:

&#13;
&#13;
let state = {
  a: 1,
  arr: [
    {text:1, id:1, completed: true},
    {text:2, id:2, completed: false}
  ]
}

console.log('old values', JSON.stringify(state));

// updating the values

let newState = {
   ...state,
   arr: [{completed: true}]
}

console.log('new state = ', newState);
&#13;
&#13;
&#13;

答案 2 :(得分:1)

React的一个开创性设计原则是“不要改变状态”。如果要更改数组中的数据,则需要创建具有更改值的新数组。

例如,我有一个州的结果数组。最初我只是为构造函数中的每个索引设置值为0.

this.state = {           
       index:0,
        question: this.props.test[0].questions[0],
        results:[[0,0],[1,0],[2,0],[3,0],[4,0],[5,0]],
        complete: false         
};

稍后,我想更新数组中的值。但我不会在状态对象中更改它。使用ES6,我们可以使用扩展运算符。数组切片方法返回一个新数组,它不会更改现有数组。

updateArray = (list, index,score) => {
   // updates the results array without mutating it
      return [
        ...list.slice(0, index),
        list[index][1] = score,
       ...list.slice(index + 1)
     ];
};

当我想更新数组中的项目时,我调用updateArray并一次性设置状态:

this.setState({
        index:newIndex, 
        question:this.props.test[0].questions[newIndex],
        results:this.updateArray(this.state.results, index, score)
});