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

Fil*_*lth 14 javascript state reducers reactjs redux

我有一个待办事项列表,并希望如果用户点击"完成",则将数组中该项目的状态设置为"完成".

这是我的行动:

export function completeTodo(id) {
    return {
        type: "COMPLETE_TASK",
        completed: true,
        id
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的减速机:

case "COMPLETE_TASK": {
             return {...state,
                todos: [{
                    completed: action.completed
                }]
             }
        }
Run Code Online (Sandbox Code Playgroud)

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

Objecttodos: Array[1]
    0: Object
        completed: false
        id: 0
        text: "Initial todo"
    __proto__: Object
    length: 1
    __proto__: Array[0]
    __proto__: Object
Run Code Online (Sandbox Code Playgroud)

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

Tom*_*omW 49

您需要转换您的待办事项数组以更新相应的项目.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
        ) 
    };
Run Code Online (Sandbox Code Playgroud)

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

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


May*_*kla 8

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

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

解决方案:

1-使用array.map找到正确的元素然后更新值,像这样:

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

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}
Run Code Online (Sandbox Code Playgroud)

检查此代码段,您将更好地了解您正在犯的错误:

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