DTek
DTek

Reputation: 371

Component with form keeps refreshing page in ReactJS

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

Answers (2)

Votemike
Votemike

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

Tholle
Tholle

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

Related Questions