Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

localStorage is saving my data but after refresh is reseting and empty it

I have a problem and I need you to help me understand it. I am using ReactJS and I am building a simple CRUD Todo App. I Want to store my todos in local storage. The data is saved there and I can see it but after the refresh it is emptying my local storage.

What am I doing wrong? Something that I notice is that from the first time when I open the app (first rendering), local storage is creating the storage space without adding a todo.

Could I have missed something in my code that makes it reset it or empty it when the page is rendered?

import React, { useState, useEffect } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faCheck,
  faPen,
  faPlus,
  faTrashCan,
} from "@fortawesome/free-solid-svg-icons";
import "./App.css";
import { faCircleCheck } from "@fortawesome/free-regular-svg-icons";

function App() {
  const [todos, setTodos] = useState([]);
  const [todo, setTodo] = useState("");

  const [todoEditing, setTodoEditing] = useState(null);
  const [editingText, setEditingText] = useState("");

  useEffect(() => {
    const json = window.localStorage.getItem("todos");
    const loadedTodos = JSON.parse(json);
    if (loadedTodos) {
      setTodos(loadedTodos);
    }
  }, []);

  useEffect(() => {
    const json = JSON.stringify(todos);
    window.localStorage.setItem("todos", json);
  }, [todos]);

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

    const newTodo = {
      id: new Date().getTime(),
      text: todo,
      completed: false,
    };

    setTodos([...todos].concat(newTodo));
    setTodo("");
  }

  function deleteTodo(id) {
    const updatedTodos = [...todos].filter((todo) => todo.id !== id);
    setTodos(updatedTodos);
  }

  function toggleComplete(id) {
    let updatedTodos = [...todos].map((todo) => {
      if (todo.id === id) {
        todo.completed = !todo.completed;
      }
      return todo;
    });
    setTodos(updatedTodos);
  }

  function submitEdits(id) {
    const updatedTodos = [...todos].map((todo) => {
      if (todo.id === id) {
        todo.text = editingText;
      }
      return todo;
    });
    setTodos(updatedTodos);
    setTodoEditing(null);
  }

  return (
    <div className="App">
      <div className="app-container">
        <div className="todo-header">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              name="todo-input-text"
              placeholder="write a todo..."
              onChange={(e) => {
                setTodo(e.target.value);
              }}
              value={todo}
            />
            <button>
              <FontAwesomeIcon icon={faPlus} />
            </button>
          </form>
        </div>
        <div className="todo-body">
          {todos.map((todo) => {
            return (
              <div className="todo-wrapper" key={todo.id}>
                {todo.id === todoEditing ? (
                  <input
                    className="edited-todo"
                    type="text"
                    onChange={(e) => setEditingText(e.target.value)}
                  />
                ) : (
                  <p className={todo.completed ? "completed" : "uncompleted"}>
                    {todo.text}
                  </p>
                )}
                <div className="todo-buttons-wrapper">
                  <button onClick={() => toggleComplete(todo.id)}>
                    <FontAwesomeIcon icon={faCircleCheck} />
                  </button>
                  {todo.id === todoEditing ? (
                    <button onClick={() => submitEdits(todo.id)}>
                      <FontAwesomeIcon icon={faCheck} />
                    </button>
                  ) : (
                    <button onClick={() => setTodoEditing(todo.id)}>
                      <FontAwesomeIcon icon={faPen} />
                    </button>
                  )}
                  <button
                    onClick={() => {
                      deleteTodo(todo.id);
                    }}
                  >
                    <FontAwesomeIcon icon={faTrashCan} />
                  </button>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

export default App;

from the first render is allocating the space

after I add a todo ass you can see is saving it to my local storage but after the refresh is empty just like in the first image

like image 272
ispasDani Avatar asked Oct 31 '25 00:10

ispasDani


2 Answers

You should be loading todos from localStorage on the Component mount if they are available in localStorage like this,

const loadedTodos = localStorage.getItem("todos")
  ? JSON.parse(localStorage.getItem("todos"))
  : []; // new

const [todos, setTodos] = useState(loadedTodos); // updated

And then you don't have to mutate the state using setTodos(loadedTodos) in the useEffect.

Just remove this useEffect , from the code:

// that useEffect should be removed
useEffect(() => {
    const json = window.localStorage.getItem("todos");
    const loadedTodos = JSON.parse(json);
    if (loadedTodos) {
      setTodos(loadedTodos);
    }
  }, []);

You can check this in the working CodeSandbox as well.

like image 195
Faisal Nazik Avatar answered Nov 02 '25 15:11

Faisal Nazik


I think your second useEffect is causing it to reset.

Move that the useEffect logic to a separate function.

And instead of calling setTodos, call that function, update the storage, and then call setTodos from that function.

like image 37
Jordan Avatar answered Nov 02 '25 14:11

Jordan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!