React useReducer 不更新数组中的对象
React useReducer not updating object in array
待办事项组件:
import React, { useReducer, useState } from 'react';
import Todo2 from './Todo2';
export const ACTIONS = {
ADD_TODO : 'add-todo',
TOGGLE_TODO : 'toggle-todo'
};
function reducer(state, action) {
switch(action.type) {
case ACTIONS.ADD_TODO:
return [...state, {id: Date.now(), name: action.payload.name, complete: false}];
case ACTIONS.TOGGLE_TODO:
const patch = [...state];
console.log('The index is:', action.payload.index);
console.log('The current state is:', patch[action.payload.index].complete);
// update state
patch[action.payload.index].complete = !patch[action.payload.index].complete;
console.log('The updated state is:', patch[action.payload.index].complete);
console.log('The patch is:', patch);
return patch;
}
}
export default function Todos() {
const [todos, dispatch] = useReducer(reducer, []);
const [name, setName] = useState('');
function handleSubmit(e) {
e.preventDefault();
dispatch({type: ACTIONS.ADD_TODO, payload: {name: name}});
setName('');
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={e => setName(e.target.value)}/>
</form>
{todos.map((todo, i) => <Todo2 key={todo.id} todo={todo} index={i} dispatch={dispatch} />)}
</div>
);
}
待办事项组件:
import React from 'react';
import { ACTIONS } from './Todos2';
export default function Todo2({ todo, dispatch, index }) {
return (
<div>
<span style={{color: todo.complete ? 'green':'red' }}>{todo.name}</span>
<button onClick={e => dispatch({type: ACTIONS.TOGGLE_TODO, payload : {index: index}})}>Toggle</button>
</div>
)
}
我正在尝试更新数组中的对象,根据其当前值将其“完整”属性 设置为 true 或 false。我 console.logged 结果,但最后补丁永远不会得到它的更新数据,它总是保留它的原始值。
如果我像这样更新状态,它会起作用,但我不知道为什么会起作用,但更新索引的方式不起作用。
// update state
patch[action.payload.index].complete = true;
我创建了一个 codesandbox 示例并重现了同样的问题,然后我将 const patch = [...state]
更改为:
import _ from 'lodash'
...
...
const patch = _.cloneDeep(state)
而且,其他一切都保持不变,它就像一个魅力。这是 code 现在我知道,传播运算符 ...
确实创建了一个 浅拷贝 而不是 深拷贝 .因此,我认为您的 !patch[action.payload.index].complete
在同一行中更新,创建了一个矛盾的分配(如双重更新)。找不到技术参考来更好地解释这一点,但问题肯定是没有深度复制对象。
建议
case ACTIONS.TOGGLE_TODO:
return state.map((el, idx) => idx === action.payload.index ? {...el, complete: !el.complete} : el)
待办事项组件:
import React, { useReducer, useState } from 'react';
import Todo2 from './Todo2';
export const ACTIONS = {
ADD_TODO : 'add-todo',
TOGGLE_TODO : 'toggle-todo'
};
function reducer(state, action) {
switch(action.type) {
case ACTIONS.ADD_TODO:
return [...state, {id: Date.now(), name: action.payload.name, complete: false}];
case ACTIONS.TOGGLE_TODO:
const patch = [...state];
console.log('The index is:', action.payload.index);
console.log('The current state is:', patch[action.payload.index].complete);
// update state
patch[action.payload.index].complete = !patch[action.payload.index].complete;
console.log('The updated state is:', patch[action.payload.index].complete);
console.log('The patch is:', patch);
return patch;
}
}
export default function Todos() {
const [todos, dispatch] = useReducer(reducer, []);
const [name, setName] = useState('');
function handleSubmit(e) {
e.preventDefault();
dispatch({type: ACTIONS.ADD_TODO, payload: {name: name}});
setName('');
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={e => setName(e.target.value)}/>
</form>
{todos.map((todo, i) => <Todo2 key={todo.id} todo={todo} index={i} dispatch={dispatch} />)}
</div>
);
}
待办事项组件:
import React from 'react';
import { ACTIONS } from './Todos2';
export default function Todo2({ todo, dispatch, index }) {
return (
<div>
<span style={{color: todo.complete ? 'green':'red' }}>{todo.name}</span>
<button onClick={e => dispatch({type: ACTIONS.TOGGLE_TODO, payload : {index: index}})}>Toggle</button>
</div>
)
}
我正在尝试更新数组中的对象,根据其当前值将其“完整”属性 设置为 true 或 false。我 console.logged 结果,但最后补丁永远不会得到它的更新数据,它总是保留它的原始值。
如果我像这样更新状态,它会起作用,但我不知道为什么会起作用,但更新索引的方式不起作用。
// update state
patch[action.payload.index].complete = true;
我创建了一个 codesandbox 示例并重现了同样的问题,然后我将 const patch = [...state]
更改为:
import _ from 'lodash'
...
...
const patch = _.cloneDeep(state)
而且,其他一切都保持不变,它就像一个魅力。这是 code 现在我知道,传播运算符 ...
确实创建了一个 浅拷贝 而不是 深拷贝 .因此,我认为您的 !patch[action.payload.index].complete
在同一行中更新,创建了一个矛盾的分配(如双重更新)。找不到技术参考来更好地解释这一点,但问题肯定是没有深度复制对象。
建议
case ACTIONS.TOGGLE_TODO:
return state.map((el, idx) => idx === action.payload.index ? {...el, complete: !el.complete} : el)