[英]Checkbox not changing state in React component
我正在使用 React 创建一个 todolist 应用程序。 待办事项的数据如下所示:
const todoData = [
{
id: 1,
text: "Empty bin",
completed: true
},
{
id: 2,
text: "Call mom",
completed: false
}
]
现在,我有一个 App 组件,我可以在其中导入该数据并将其保存在状态中。
import todoData from "./todoData"
class App extends React.Component {
constructor() {
super()
this.state = {
todos: todoData,
}
this.handleChange = this.handleChange.bind(this)
}
...
我还有一个 handleChange 方法,它应该将完成的属性的值更改为其相反的值。 例如:对于 id 为 1 的待办事项,它的文本值为“Empty Bin”,并且已完成为 true,因此默认情况下将选中复选框。 但是,当它被点击时,完成应该是假的,并且不再点击复选框。 出于某种原因,这不会发生,因此完成保持其默认布尔值并且不会翻转。 因此,当单击复选框时不会发生任何变化。
handleChange(id) {
this.setState(prevState => {
const updatedTodos = prevState.todos.map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed
}
return todo
})
return {
todos: updatedTodos
}
})
}
使用 console.log 后,我意识到 todo.completed 确实被更改为其相反的值,但由于某种原因,它没有在 updatedTodos 中更改,即使在 devtools map() 中说当它返回一个新数组时该值已更新存储在 updatedTodos 中。 因此,状态不会改变并且无法单击复选框
TodoItem 功能组件与 App 组件位于一个单独的文件中,并包含 todo 元素的 HTML。 如下图所示:
function TodoItem(props) {
return (
<div className="todo-item">
<input type="checkbox"
checked={props.task.completed}
onChange={() => props.handleChange(props.task.id)}/>
<p>{props.task.text}</p>
</div>
)
}
此外,TodoItem 是在 App 组件中呈现的
render() {
const todoArray = this.state.todos.map(task => <TodoItem key={task.id}
task={task} handleChange={this.handleChange}/>)
return (
<div className="todo-list">
{todoArray}
</div>
)
}
看起来你正在改变handleChange
函数中的 todo 对象
handleChange(id) {
this.setState(prevState => {
const updatedTodos = prevState.todos.map(todo => {
if (todo.id === id) {
//todo.completed = !todo.completed this is mutating
// in react mutating a object will result in unexpected results like this.
// so you have to create a new object based on the current todo and return it
return {
...todo,
completed: !todo.completed
}
}
return todo
})
return {
todos: updatedTodos
}
})
}
那里发生了什么?
数组中的每个对象都指向一个内存位置,基本上,如果我们更改对象属性值(例如: completed
),而不更改它正在变异的内存位置,
并通过这样做todo.completed = !todo.completed
我们直接改变的值completed
属性,但仍指向同一个内存位置的待办事项对象,所以我们做这个变异的对象,反应也不会对此作出回应,现在
return {
...todo, // <- create a new object based on todo
completed: !todo.completed // <- change the completed property
}
我们创建基于待办事项的新对象{...todo}
(新对象=新的存储位置),和我们改变的值completed
=> {...todo, completed: !todo.completed}
因为这是指向新的内存位置 react 会响应变化。
如果您不熟悉扩展运算符 ( ...
),请在此处阅读,不要忘记查看那里的对象文字部分中的扩展
你需要传播你的对象然后改变特定的领域
if (todo.id === id) {
return {
...todo,
completed: !todo.completed
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.