更新项目数组中的单个值 |反应减少
Update single value in item array | react redux
我有一个待办事项列表,如果用户单击 "complete",我想将数组中该项目的状态设置为 "complete"。
这是我的操作:
export function completeTodo(id) {
return {
type: "COMPLETE_TASK",
completed: true,
id
}
}
这是我的减速器:
case "COMPLETE_TASK": {
return {...state,
todos: [{
completed: action.completed
}]
}
}
我遇到的问题是新状态不再有与所选项目上的待办事项关联的文本,ID 也不再存在。这是因为我正在覆盖状态并忽略以前的属性吗?我的对象项目加载看起来像这样:
Objecttodos: Array[1]
0: Object
completed: false
id: 0
text: "Initial todo"
__proto__: Object
length: 1
__proto__: Array[0]
__proto__: Object
如您所见,我只想将已完成的值设置为 true。
您需要转换待办事项数组以更新相应的项目。 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/),它通过 updateIn
和 setIn
方法解决了这个问题(对于有很多的大型对象,它们比普通对象和数组更有效键和数组,但对于小的键较慢)。
New state does no longer have the text associated of that todo item on
the selected item and the ID is no longer there, Is this because I am
overwriting the state and ignoring the previous properties?
是的,因为在每次更新期间,您分配的新数组只有 一个 键 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}
检查此代码段,您将更好地了解您正在犯的错误:
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);
React 的开创性设计原则之一是"Don't mutate state."如果你想改变数组中的数据,你想用改变后的值创建一个新数组。
例如,我在状态中有一组结果。最初我只是将构造函数中每个索引的值设置为 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 中,我们可以使用扩展运算符。数组切片方法returns一个新数组,它不会改变现有数组。
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)
});
我有一个待办事项列表,如果用户单击 "complete",我想将数组中该项目的状态设置为 "complete"。
这是我的操作:
export function completeTodo(id) {
return {
type: "COMPLETE_TASK",
completed: true,
id
}
}
这是我的减速器:
case "COMPLETE_TASK": {
return {...state,
todos: [{
completed: action.completed
}]
}
}
我遇到的问题是新状态不再有与所选项目上的待办事项关联的文本,ID 也不再存在。这是因为我正在覆盖状态并忽略以前的属性吗?我的对象项目加载看起来像这样:
Objecttodos: Array[1]
0: Object
completed: false
id: 0
text: "Initial todo"
__proto__: Object
length: 1
__proto__: Array[0]
__proto__: Object
如您所见,我只想将已完成的值设置为 true。
您需要转换待办事项数组以更新相应的项目。 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/),它通过 updateIn
和 setIn
方法解决了这个问题(对于有很多的大型对象,它们比普通对象和数组更有效键和数组,但对于小的键较慢)。
New state does no longer have the text associated of that todo item on the selected item and the ID is no longer there, Is this because I am overwriting the state and ignoring the previous properties?
是的,因为在每次更新期间,您分配的新数组只有 一个 键 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}
检查此代码段,您将更好地了解您正在犯的错误:
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);
React 的开创性设计原则之一是"Don't mutate state."如果你想改变数组中的数据,你想用改变后的值创建一个新数组。
例如,我在状态中有一组结果。最初我只是将构造函数中每个索引的值设置为 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 中,我们可以使用扩展运算符。数组切片方法returns一个新数组,它不会改变现有数组。
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)
});