Ad
Update Field In State Array Object
I am building a simple TODO app in React. I have a todos
array in the state, and each todo
has a flag completed
. When an item is clicked, I want to toggle the completed
flag of that todo
. Here's what I've done so far:
Todos.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>
);
}
}
Todo.js is just a simple component (yes, it could be functional as well)
class Todo extends React.Component {
render() {
return (
<div onClick={() => this.props.todoClicked(this.props.id)}>
{this.props.todo.title}
</div>
);
}
}
In Todos.js the function onTodoClicked
is called and it prints out the correct id, but nothing else changes in the state (I inspected the clicked object both with React dev tools and console.log's). The clicked item doesn't change its completed
flag. What am I doing wrong?
Ad
Answer
That's how it should look:
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>
Ad
source: stackoverflow.com
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?
Ad