Reputation: 15
I'm brand new to Reactjs and I'm working on my first app, a todo app of course. However, everything was going smoothly until I was asked to create a delete button to remove my todos. I'm stuck and have been puzzled over this for almost 3 days. Any help or advice would be appreciated.
react-to-do/src/App.js
import React, { Component } from "react";
import "./App.css";
import ToDo from "./components/ToDo.js";
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{ description: "Walk the cat", isCompleted: true },
{ description: "Throw the dishes away", isCompleted: false },
{ description: "Buy new dishes", isCompleted: false }
],
newTodoDescription: ""
};
this.deleteTodo = this.deleteTodo.bind(this);
}
deleteTodo(description) {
this.setState({
todos: this.state.todos.filter(
(todos, index) => todos.description !== description
)
});
}
handleChange(e) {
this.setState({ newTodoDescription: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.newTodoDescription) {
return;
}
const newTodo = {
description: this.state.newTodoDescription,
isCompleted: false
};
this.setState({
todos: [...this.state.todos, newTodo],
newTodoDescription: ""
});
}
toggleComplete(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false : true;
this.setState({ todos: todos });
}
render() {
return (
<div className="App">
<ul>
{this.state.todos.map((todo, index) => (
<ToDo
key={index}
description={todo.description}
isCompleted={todo.isCompleted}
toggleComplete={() => this.toggleComplete(index)}
/>
))}
</ul>
<form onSubmit={e => this.handleSubmit(e)}>
<input
type="text"
value={this.state.newTodoDescription}
onChange={e => this.handleChange(e)}
/>
<input type="submit" />
</form>
</div>
);
}
}
export default App;
react-to-do/src/ToDo.js
import React, { Component } from "react";
class ToDo extends Component {
deleteToDo(description) {
this.props.deleteToDo(description);
}
render() {
return (
<div className="wrapper">
<button
className="deleteToDo"
onClick={e => this.deleteToDo(this.props.description)}
>
Delete
</button>
{this.props.deleteToDo}
<li>
<input
type="checkbox"
checked={this.props.isCompleted}
onChange={this.props.toggleComplete}
/>
<span>{this.props.description}</span>
</li>
</div>
);
}
}
export default ToDo;
react-to-do/src/index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
ReactDOM.render(<App />, document.getElementById("root"));
registerServiceWorker();
Upvotes: 0
Views: 164
Reputation: 1043
Your code should look like
class ToDo extends React.Component {
deleteToDo(description) {
this.props.deleteToDo(description);
}
render() {
return (
<div className="wrapper">
<button className="deleteToDo" onClick = {(e) =>
this.deleteToDo(this.props.description)}>Delete</button>
{() => this.props.deleteToDo(this.props.description)}
<li>
<input type="checkbox" checked={ this.props.isCompleted }
onChange={ this.props.toggleComplete } />
<span>{ this.props.description }</span>
</li>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
todos: [
{ description: 'Walk the cat', isCompleted: true },
{ description: 'Throw the dishes away', isCompleted: false },
{ description: 'Buy new dishes', isCompleted: false }
],
newTodoDescription: ''
};
this.deleteTodo = this.deleteTodo.bind(this);
}
deleteTodo(description) {
const filteredTodos = this.state.todos.filter((todo, index) => todo.description !== description);
this.setState({
todos: filteredTodos
});
}
handleChange(e) {
this.setState({ newTodoDescription: e.target.value })
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.newTodoDescription) { return }
const newTodo = { description: this.state.newTodoDescription,
isCompleted: false};
this.setState({ todos: [...this.state.todos, newTodo],
newTodoDescription: '' });
}
toggleComplete(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false: true;
this.setState({ todos: todos });
}
render() {
return (
<div className="App">
<ul>
{ this.state.todos.map( (todo, index) =>
<ToDo key={ index } description={ todo.description }
isCompleted={ todo.isCompleted } toggleComplete={ () =>
this.toggleComplete(index) } deleteToDo={this.deleteTodo} />
)}
</ul>
<form onSubmit={ (e) => this.handleSubmit(e) }>
<input type="text" value={
this.state.newTodoDescription } onChange={ (e) =>
this.handleChange(e) } />
<input type="submit" />
</form>
</div>
);
}
}
Here you forgot to pass props
from App
and description
parameter from ToDo
component.
Try here https://jsfiddle.net/prakashk/69z2wepo/101369/#&togetherjs=B3l5GDzo8A
Upvotes: 1
Reputation: 6581
You never pass your "deleteTodo" function as a prop to your "toDo" component. change the portion where you create you're todo components in that map to resemble something like this...
map.... => <toDo deleteToDo={this.deleteTodo}......... />
remember components are scoped to themselves if you want to call a function that exists in the parents context in a child, a reference of that function must be passed to that child as a prop.
Upvotes: 1