Reputation: 371
I'm attempting at creating a simple todo app to try to cement some concepts. This app gets some previous todos from a .js file with json object. And every time they get clicked they are deleted from the current app.
Now I wanted to add the ability to add todos, first to the current instance of app itself and afterwards to the file to ensure continuity.
My problem arises adding to the app instance.
When using the component with a form, it all goes south.
I tried putting all the component parts in the App.js main file but still the same result, it refreshes after the alert(value) line.
I've also tried changing the order inside the addTodo function and the alert only works if it's the first line of the function, anywhere else the refresh happens before it. So I assumed it's something about using the state of the app component?
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import todosData from "./todosData"
import TodoItem from "./TodoItem"
import TodoForm from './TodoForm'
class App extends Component {
constructor() {
super()
this.state = {
todos: todosData
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(id) {
const allTodos = this.state.todos
const filtered = allTodos.filter(x => x.id !== id)
const filtered2 = filtered
filtered2.push({id:4,text:"HAKUNA MATATA",completed:false })
this.setState({todos:filtered2})
//added testing so that whenever I delete a todo it adds one with "HAKUNA MATATA"
}
addTodo(value) {
alert(value)
const allTodos = this.state.todos
const lastTodo = this.state.todos.slice(-1)[0]
const newId = lastTodo.id + 1
const newTodo = {id: newId, text: value, completed:false}
allTodos.push(newTodo)
this.setState({todos:allTodos})
}
render() {
const todoItems = this.state.todos.map( item =>
<TodoItem
key={item.id}
item={item}
handleChange={this.handleChange}
/>
)
const text = ""
return (
<div className="todo-list">
{todoItems}
<TodoForm addTodo={this.addTodo}/>
</div>
);
}
}
export default App;
TodoForm.js
import React from 'react'
class TodoForm extends React.Component {
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(event) {
this.props.addTodo(this.input.value)
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
</label>
<input type="text" ref={(input) => this.input = input}/>
</form>
)
}
}
export default TodoForm
Can you guys help me with this? From what I understood preventDefault was supposed to prevent this?
Upvotes: 2
Views: 2294
Reputation: 872
In case anyone comes to this answer from Google:
In my case, when I submitted the form, I lazy loaded a component underneath, but it had not been wrapped in <Suspense>
. Adding that fixed my issue.
Upvotes: 0
Reputation: 112777
Call the preventDefault
method on the event the first thing you do in handleSubmit
and it should work.
handleSubmit(event) {
event.preventDefault()
this.props.addTodo(this.input.value)
}
You also need to bind the addTodo
method to this
in the App
constructor.
class App extends Component {
constructor() {
super()
this.state = {
todos: todosData
}
this.handleChange = this.handleChange.bind(this)
this.addTodo = this.addTodo.bind(this)
}
// ...
}
Upvotes: 3