我正在React中构建一个简单的TODO应用。我在状态中有一个todos
数组,并且每个todo
都有一个标志completed
。单击某个项目后,我想切换该completed
的{{1}}标志。到目前为止,这是我所做的:
Todos.js
todo
Todo.js 只是一个简单的组件(是的,它也可以起作用)
class Todos extends React.Component {
constructor() {
super();
this.state = {
todos: [
{ id:0, title:"Title 0", completed:false },
{ id:1, title:"Title 1", completed:true }
]
};
this.onTodoClicked = this.onTodoClicked.bind(this);
}
onTodoClicked(id) {
console.log(id + " clicked");
this.setState(prevState => {
todos: prevState.todos.map((item, index) => {
return index !== id ? item : { ...item, completed: !item.completed };
});
});
}
render() {
return (
<div>
{this.state.todos.map((todoItem, key) => (
<Todo id={key} key={key} todo={todoItem}
todoClicked={this.onTodoClicked} />
))}
</div>
);
}
}
在 Todos.js 中,调用了函数class Todo extends React.Component {
render() {
return (
<div onClick={() => this.props.todoClicked(this.props.id)}>
{this.props.todo.title}
</div>
);
}
}
,它会打印出正确的ID,但是状态没有其他变化(我使用React开发工具和console.log)。单击的项目不会更改其onTodoClicked
标志。我在做什么错了?
答案 0 :(得分:2)
最好依靠id
而不是index
:
return item.id !== id ? item : { ...item, completed: !item.completed };
对于Todo
id,您还应该传递id,而不是密钥(id={key}
)(或仅传递整个todoItem):
id={todoItem.id}
对于Todo
键也要传递id
,因为传递相同的key
索引,您的Todo
项可能不会被重新呈现。
最后,您在prevState => ({
class Todo extends React.Component {
render() {
return (
<div onClick={() => this.props.todoClicked(this.props.todo.id)}>
{this.props.todo.title} - {this.props.todo.completed.toString()}
</div>
);
}
}
class Todos extends React.Component {
constructor() {
super();
this.state = {
todos: [
{ id:0, title:"Title 0", completed:false },
{ id:1, title:"Title 1", completed:true }
]
};
this.onTodoClicked = this.onTodoClicked.bind(this);
}
onTodoClicked(id) {
console.log(id);
this.setState(prevState => ({
todos: prevState.todos.map((item, index) => {
return item.id !== id ? item : { ...item, completed: !item.completed };
})
}));
}
render() {
return (
<div>
{this.state.todos.map((todoItem, key) => (
<Todo key={todoItem.id} todo={todoItem}
todoClicked={this.onTodoClicked} />
))}
</div>
);
}
}
ReactDOM.render(<Todos />, document.querySelector("#container"))
<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="container"></div>
答案 1 :(得分:1)
那是它的外观:
class Todos extends React.Component {
constructor() {
super();
this.state = {
todos: [
{ id:0, title:"Title 0", completed:false },
{ id:1, title:"Title 1", completed:true }
]
};
this.onTodoClicked = this.onTodoClicked.bind(this);
}
onTodoClicked(id) {
console.log(id + " clicked");
this.setState(prevState => ({
todos: prevState.todos.map((item, index) => {
return item.id !== id ? item : { ...item, completed: !item.completed };
})
}));
}
render() {
return (
<div>
{this.state.todos.map((todoItem, key) => (
<Todo key={key} todo={todoItem}
todoClicked={this.onTodoClicked} />
))}
</div>
);
}
}
class Todo extends React.Component {
render() {
return (
<div onClick={() => this.props.todoClicked(this.props.todo.id)}>
{this.props.todo.title} {this.props.todo.completed && "completed"}
</div>
);
}
}
ReactDOM.render(<Todos/>, document.getElementById("root"))
<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>
答案 2 :(得分:0)
您必须在 onTodoClicked 函数中进行更改。它将起作用。
onTodoClicked(id) {
console.log(id + " clicked");
this.state.todos[id].completed = !this.state.todos[id].completed;
this.setState({ todos: this.state.todos });
console.log("state,", this.state.todos);
}
答案 3 :(得分:0)
这是您在Todo.js中可以做的
class Todo extends React.Component {
render() {
return (
<div onClick={() => this.props.todoClicked(this.props.todo.id)}>
{this.props.todo.title}
</div>
);
}
}
在onTodoClicked函数中,您可以执行以下操作。
onTodoClicked(id) {
this.setState(prevState => {
todos: prevState.todos.map((item) => {
return item.id !== id ? item : { ...item, completed: !item.completed };
});
});
}
我希望这会对您有所帮助。