Element not updating setState

Hi, I’m working on a small simple project and the whole idea is to be able to add and delete todos. But the problem I’m having is when I enter the data into a input field the event handler adds a new todo when I console log it but the UI is not updated in the browser? So in the input event handler(handleSubmit) when I reset the input value after changing the state of todo then it updates the UI Element in the browser. Same goes with the delete button but this time resetting the input doesn’t delete the todo but instead typing any keyword on a input filed deletes the UI that was clicked to delete. Not sure what I’m missing here? Any help would be very appreciated. Thank you.

Code:

This is the todo.jsx file

import React, { useState } from "react";
import { useEffect } from "react";
import { addTodo, getTodos, todoDelete } from "../fakeTodosService";

export default function Todo() {
  const [input, setInput] = useState("");
  const [todos, setTodos] = useState([]);
  const [error, setError] = useState("");

  useEffect(() => {
    setTodos(getTodos());
  }, []);

  function handleDelete(list) {
    setTodos(todoDelete(list));
  }

  function handleSubmit(e) {
    e.preventDefault();

    if (input.trim() === "") setError("Enter value first!");
    else {
      setError("");
      setTodos(addTodo(input));
      setInput("");    //when this is removed the newly added todo won't show in the browser
    }
  }

  function handleChange({ currentTarget: input }) {
    const inputValue = input.value;
    setInput(inputValue);
  }

  return (
    <div className="vh-100 vw-100" style={{ backgroundColor: "#F8F8F8" }}>
      <div className="pt-5">
        <h2>To-Do Lists</h2>
      </div>
      <div className="w-100 h-100 p-5">
        <form onSubmit={handleSubmit}>
          <div className="row w-100">
            <div className="col">
              <input
                className="form-control"
                type="text"
                placeholder="Enter To-do's"
                name="todo"
                id="todo"
                onChange={handleChange}
              />
              {error && <div className="alert alert-danger">{error}</div>}
            </div>
            <button className="btn btn-primary col-1" onClick={handleSubmit}>
              Add
            </button>
          </div>
        </form>
        {todos.length === 0 ? (
          <h3>There are no To-do's in the Database</h3>
        ) : (
          <table className="table table-striped mt-5">
            <tbody>
              {todos.map((list) => (
                <tr key={list._id}>
                  <td>{list.body}</td>
                  <td>
                    <button
                      className="btn btn-danger"
                      onClick={() => handleDelete(list)}
                    >
                      Delete
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

this is the fakeTodoService file "

const todos = [
  {
    _id: "1",
    body: "Wash Clothes",
  },
  {
    _id: "2",
    body: "Fold Clothes",
  },
  {
    _id: "3",
    body: "Clean Apartment",
  },
  {
    _id: "4",
    body: "Learn React",
  },
  {
    _id: "5",
    body: "Learn Node.js",
  },
  {
    _id: "6",
    body: "Start Project",
  },
];

export function getTodos() {
  return todos;
}

export function addTodo(input) {
  const todo = {};
  todo._id = Date.now() + Math.floor(Math.random() * 99);
  todo.body = input;
  todos.push(todo);
  return todos;
}

export function todoDelete(list) {
  const index = todos.indexOf(list);
  todos.splice(index, 1);
  return todos;
}

You should declare id at the top if the file like so:

let lastId = 0;

And then when creating the Todo item, you can use it and increment it.

As for the bug, I think you should make some changes to the addTodo function.

Instead of writing todos.push(todo), you can try writing return [...todos, todo] .

1 Like

Hey its Harvel, do you want to change the UI as you change the input value or only on submission? I’ve got a solution for both