您好,我正在使用React上下文,但是遇到了问题。
我拥有包含所有逻辑的组件:
import React , {useContext} from 'react';
import {TodoContext} from '../../contexts/todo-context';
import Todo from './Todo';
import './Todos.css';
export default function TodoList() {
const [todos , setTodos] = useContext(TodoContext);
const markComplete = (e) => {
setTodos(prevState => [...prevState , {...e.target.value , done:true} ]);
console.log(todos);
}
return (
<div className="TodoContainer">
{todos.map(todo => (<Todo key={todo.id} todo={todo} markComplete={markComplete} /> ))}
</div>
)
}
我正在传递一个markComplete函数,该函数将在Todo组件中使用。
Todo组件:
从“反应”导入React
export default function Todo({todo , markComplete}) {
return (
<div>
<input type="checkbox" value={todo} onChange={markComplete}></input>
<li>{todo.title}</li>
<div className="spacer"></div>
</div>
)
}
在这里,我有一个复选框,其中onChange应该会触发我的markComplete函数。这行得通,但是markComplete函数由于某种原因不会改变我的状态。再次是该功能:
const markComplete = (e) => {
setTodos(prevState => [...prevState , {...e.target.value , done:true} ]);
console.log(todos);
}
它还会生成一条错误消息,提示我应将密钥传递给我(我已经在这样做了)
状态:
const [todo, setTodo] = useState([
{
title : 'Do the dishes',
done : false ,
id: 123
},
{
title : 'wash car',
done : false ,
id: 423
},
{
title : 'Buy pen',
done : false ,
id: 323
}
]);
答案 0 :(得分:1)
更新状态的方法是错误的。
请注意,您在待办事项中做到了:
<input type="checkbox" value={todo} onChange={markComplete}></input>
todo
本身是一个对象,这意味着在执行此操作时:
setTodos(prevState => [...prevState , {...e.target.value , done:true} ]);
您基本上错误地散布了该物体。实际上,下一个状态更新的结果是更新:
0: {title: "Do the dishes", done: false, id: 123}
1: {title: "wash car", done: false, id: 423}
2: {title: "Buy pen", done: false, id: 323}
3: {0: "[", 1: "o", 2: "b", 3: "j", 4: "e", 5: "c", 6: "t", 7: " ", 8: "O", 9: "b", 10: "j", 11: "e", 12: "c", 13: "t", 14: "]", done: true}
这说明了您遇到的unique key
错误。
一种可能的解决方案是对更改处理程序使用包装,该包装传递项目ID和已检查状态:
function Todo({todo , markComplete}) {
const handleChange = React.useCallback(e => {
markComplete(todo.id, e.target.checked);
}, [todo, markComplete]);
return (
<div>
<input type="checkbox" value={todo.id} onChange={handleChange}></input>
<li>{todo.title}</li>
<div className="spacer"></div>
</div>
)
}
markComplete:
const markComplete = (id, checked) => {
setTodos(prevState => prevState.map(it => it.id === id ? ({ ...it, done: checked }) : it));
}
我还建议在上述功能中使用useCallback
。
这是一个小提琴:https://jsfiddle.net/vdzbj16a/