[英]Checkbox doesn't change its value on click in React todo application
Please help me with this I don't understand exactly where I doing wrong.请帮我解决这个问题,我不明白我做错了什么。 So when I click on the checkbox values are not changing(if it's by default
true
when I click on the click it should the false
).因此,当我单击复选框时,值不会更改(如果在单击单击时默认为
true
,则它应该为false
)。 For that in onChange
in todoList
component I am calling handleClick
function there I change the todo.completed
value(basically toggling the values).为此,在
todoList
组件的onChange
中,我正在调用handleClick
函数,在那里我更改了todo.completed
值(基本上是切换值)。
In App.js
inside the handleClick
method When do console.log(todo)
before returning from the map function value is toggling fine, but it is not updated in the updatedTodo
.在
App.js
的handleClick
方法中,当从 map 函数返回值之前执行console.log(todo)
切换正常,但它没有在updatedTodo
更新。
App.js应用程序.js
import TodosData from "./todoData";
import TodoList from "./todoList";
import "./styles.css";
class App extends Component {
constructor() {
super();
this.state = {
todos: TodosData
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(id) {
this.setState(prevState => {
const updatedTodo = prevState.todos.map(todo => {
// console.log(updatedTodo);
if(todo.id === id) {
console.log("before the opt "+todo.completed);
todo.completed = !todo.completed
console.log("after the opt "+todo.completed);
}
//console.log(todo);
return todo;
})
console.log(updatedTodo);
return {
todos: updatedTodo
}
});
}
render() {
const todoDataComponents = this.state.todos.map(item => {
return <TodoList key = {item.id} item = {item} handleChange = {this.handleChange} />
})
return (
<div className="todo-list">{todoDataComponents}</div>
);
}
}
export default App;
todoList.jsx待办事项列表.jsx
class TodoList extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
// console.log(this.props)
return (
<div className="todo-item">
<input
type="checkbox"
checked={this.props.item.completed}
onChange = {() => this.props.handleChange(this.props.item.id)}
/>
<p>{this.props.item.text}</p>
</div>
);
}
}
export default TodoList;
todoData.js todoData.js
const TodosData = [
{ id: 1, text: "Coding", completed: true },
{ id: 2, text: "Exercise", completed: false },
{ id: 3, text: "Learning", completed: true },
{ id: 4, text: "Programming", completed: true },
{ id: 5, text: "inspire", completed: false },
{ id: 6, text: "motivation", completed: true }
];
export default TodosData;
I can't see any error in your handleChange()
method, it should work fine.我在您的
handleChange()
方法handleChange()
不到任何错误,它应该可以正常工作。 However, I've just updated some of your code which you can test below.但是,我刚刚更新了您的一些代码,您可以在下面进行测试。
I changed the name of your TodoList
as it's not really a list but an item.我更改了您的
TodoList
的名称,因为它实际上不是一个列表而是一个项目。 I also changed it to a functional component as it's only presentational, there is no need to have its own state.我还把它改成了一个功能组件,因为它只是展示性的,不需要有自己的状态。 Instead of adding a
p
tag after the input
, you should use a label
to make it accessible.与其在
input
之后添加p
标签,不如使用label
使其可访问。
I haven't really changed anything inside your handleChange()
method, only removed the console.log
s and it works as expected.我并没有真正更改您的handleChange()
方法中的任何内容,只是删除了console.log
并且它按预期工作。
Update : You're using React.StrictMode
, where React renders everything twice on dev.更新:您正在使用
React.StrictMode
,其中 React 在开发中渲染所有内容两次。 As your handleChange()
runs twice, it sets the clicked todo's completed
state twice, making it to set back to its original state.当您的
handleChange()
运行两次时,它会两次设置被点击的待办事项的completed
状态,使其设置回其原始状态。 So if it's false
on first render it sets to true
on click, but it's rendered again and on the second one it's back to false
.所以,如果这是
false
的第一渲染其设置为true
的点击,但它再次呈现和第二个它的回false
。 You won't notice it as it's pretty fast.你不会注意到它,因为它非常快。
To avoid it, you need to avoid mutating anything.为了避免它,你需要避免改变任何东西。 So I've updated your
onChange
handler, it returns a new object if the completed
property is changed.所以我更新了你的
onChange
处理程序,如果已completed
属性发生更改,它会返回一个新对象。
Feel free to run the code snippet below and click on the checkboxes or the item texts.随意运行下面的代码片段并单击复选框或项目文本。
const TodosData = [ { id: 1, text: 'Coding', completed: true }, { id: 2, text: 'Exercise', completed: false }, { id: 3, text: 'Learning', completed: true }, { id: 4, text: 'Programming', completed: true }, { id: 5, text: 'Inspire', completed: false }, { id: 6, text: 'Motivation', completed: true }, ]; function TodoItem(props) { const { handleChange, item } = props; return ( <div className="todo-item"> <input type="checkbox" id={`item-${item.id}`} checked={item.completed} onChange={() => handleChange(item.id)} /> <label htmlFor={`item-${item.id}`}>{item.text}</label> </div> ); } class App extends React.Component { constructor() { super(); this.state = { todos: TodosData, }; this.handleChange = this.handleChange.bind(this); } handleChange(id) { this.setState((prevState) => { const updatedTodo = prevState.todos.map((todo) => { return todo.id === id ? { ...todo, completed: !todo.completed, } : todo; }); return { todos: updatedTodo, }; }); } render() { const { todos } = this.state; return ( <div className="todo-list"> {todos.map((item) => ( <TodoItem key={item.id} item={item} handleChange={this.handleChange} /> ))} </div> ); } } ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') );
body { font-family: sans-serif; line-height: 1.6; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>
Instead of using an additional variable, you can do it in one line.您可以在一行中完成,而不是使用额外的变量。 Can u see if this works for you.
你能看看这是否适合你。
handleChange(id) {
this.setState(prevState => prevState.map(todo => todo.id === id ? {...todo, completed: !todo.completed} : todo )
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.