我正在使用react
和redux
创建一个todolist,当我更新redux状态数组时,它不会重新渲染,我的状态实际上是一个包含对象的数组,就像这样:
[{index:1,value:'item1',done:false}, {index:2,value:'item2',done:false}]
我想要做的是点击我想要将完成的值切换为' true', 但不知何故,我无法做到这一点。
这就是我在减速机中所做的事情:
list.map((item)=>{
if(item.index===index){
item.done=!item.done;
return [...state,list]
}
但是,即使单击切换按钮完成后,它也不会重新渲染。
似乎我不知何故正在改变国家。 请告诉我我哪里出错了,我该怎么做。
你能举出类似的例子吗?我可以正确更新简单数组的状态,但是对于包含对象的数组来说,这让我很困惑。 所以,你能举例说明吗?
这里是完整的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;
}
}
答案 0 :(得分:4)
似乎我不知何故正在改变国家。
纠正你正在改变状态,因为在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;
}
}
检查此代码段:
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);

答案 1 :(得分:1)
查看Array.prototype.Map的文档。
回调函数应该返回新数组的元素。试试这个:
return list.map(item => {
if (item.index === index) {
return {
done: !item.done
...item,
}
return item;
});
答案 2 :(得分:0)
虽然已经存在两个正确的答案,但我也希望将lodash/fp
放在这里,这样会更加密集和可读,也不会发生变异
import { set } from 'lodash/fp'
return list.map(item => {
if (item.index === index) {
return set('done', !item.done, item)
}
return item
}