Reputation: 49
Yes, I'm new to React, and I'm trying to make the (infamous?) to-do app from scratch. So far I just have a todo component and then the main app. Here's my code - first is the Todo component:
import PropTypes from 'prop-types';
class Todo extends Component {
static defaultProps = {
completed: false,
}
static propTypes = {
completed: PropTypes.bool.isRequired,
// name: PropTypes.string.isRequired,
}
constructor(props){
super(props)
this.state = {
completed: false,
}
}
render(){
return (
<div>
{!this.state.completed && <div>
<span>{this.props.name}</span>
<input type="checkbox" onClick={() => {this.markCompleted()}}/>
</div>}
</div>
)
}
markCompleted = () => {
this.setState((currentState) => {
return {
completed: !currentState.completed
}
})
}
}
export default Todo;
And then the main App component...
import React from 'react';
import Todo from './Todo';
import './App.css';
class App extends React.Component {
constructor(props){
super(props)
this.state = {
todos: [{id: 1, name: 'take out trash'}, {id: 2, name: 'feed the cat'}]
}
}
render(){
let textInput;
const todos = this.state.todos.map(todo => <Todo key={todo.id} name={todo.name} completed={todo.completed}/>)
return (
<div className="App">
<input type="text" ref={(el) => {textInput = el}} />
<button onClick={() => {this.addTodo(textInput.value)}}>Click to Add a Todo</button>
{todos}
</div>
);
}
addTodo = (todoName) => {
const newTodo = {id: this.state.todos.length + 1, name: todoName};
const todos = this.state.todos.map(todo => <Todo key={todo.id} name={todo.name} completed={todo.completed}/>)
todos.push(newTodo)
console.log(this.state.todos);
this.setState({
todos
})
// console.log(todos)
}
}
export default App;
So I'm left with a conundrum. On the initial render, the state of the todos array maps out just fine. However, when I type in a todo and click the button to add the todo, all of the names of the other todos vanish, and only the name of the last pushed todo appears. So if I were to add a todo "pay bills," then the checkboxes for "take out the trash" and "feed the cat" will still be visible, but the names of those todos will no longer be visible. I can click the checkboxes just fine to remove the todos as well, but I wish my todos array would cooperate. I think I'm also supposed to use .filter
to properly filter out todos whose completed state is marked as true
. Are the other names disappearing because of the todoName
parameter I've added in the addTodo
method? Is that causing all previous todo names to be undefined? I am really trying to learn, and I'm open to all help and suggestions to improve. I would request that we work with the code that I have already, as I've seen how other people have made the todo app before, and I don't want to just copy and observe someone else's code, because I feel that that detracts from my learning. Thanks in advance for any help!
Upvotes: 0
Views: 81
Reputation: 3400
I did some corrections on the App
class:
In addTodo
, simplify it, you can push the state array like this:
addTodo = (todoName) => {
const newTodo = {id: this.state.todos.length + 1, name: todoName};
this.setState({
todos: [...this.state.todos, newTodo]
})
console.log(this.state.todos);
}
Same for the render, you do not need that auxiliar todos you were using, just map the state like you were doing.
render(){
let textInput;
return (
<div className="App">
<input type="text" ref={(el) => {textInput = el}} />
<button onClick={() => {this.addTodo(textInput.value)}}>Click to Add a Todo</button>
{this.state.todos.map(todo => <Todo key={todo.id} name={todo.name} completed={todo.completed}/>)}
</div>
);
}
Upvotes: 1