Home > Software design >  localStorage data keeps resetting on page reload - React js
localStorage data keeps resetting on page reload - React js

Time:05-10

Error: localStorage data keeps resetting on page reload. Despite of being updated to localStorage before.

If I add new todo item, it is added to localStorage. But the updated items disappears after page reload and I get initial state value(todos).

source code: https://www.codepile.net/pile/J9L4xL9g

// App.js
// Error: localStorage data keeps resetting on page reload. Despite of being updated to localStorage before.
// If I add new todo item, it is added to localStorage. But it disappears after page reload and I get initial state value(todos). I don't know where is the problem here!

import { useState, useEffect } from "react";

function App() {
  const [todos, setTodos] = useState([{ id: 123, text: "todo 1 demo" }]);
  const [todo, setTodo] = useState("");

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

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

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

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

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

  return (
    <div className="App">
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          onChange={(e) => setTodo(e.target.value)}
          value={todo}
        />
        <button>Add todo</button>
      </form>

      {todos.map((todo) => (
        <div key={todo.id}>
          <div>{todo.text}</div>
        </div>
      ))}
    </div>
  );
}

export default App;

CodePudding user response:

You need to check the length of todos array in your useEffect function.

the callback function on useEffect will fire on each change of dependencies update

so in the first time that todos state set with its initial values, useEffect callback is fired and this is why after each reload you lose your data

  useEffect(() => {
    if (todos.length > 1) localStorage.setItem("todos", JSON.stringify(todos));
  }, [todos]);

You can fix your issue by adding this simple if condition

CodePudding user response:

The issue you were running into is that your useEffect to set the todos from the storage happens at a bad time in comparison with the one to set it.

So, instead of using an effect to grab the todos, get them synchronously with the state. This style of useState with a function argument, allows you to do a more expensive calculation for the initial creation of the state, so the function will only ever be called on initial component mounting.

  const [todos, setTodos] = useState(
    () =>
      JSON.parse(localStorage.getItem("todos")) || [
        { id: 123, text: "todo 1 demo" }
      ]
  );
  useEffect(() => {
    localStorage.setItem("todos", JSON.stringify(todos));
  }, [todos]);

In this way, you can get rid of the extra effect, and prevent a flash of incorrect UI between the initial code run and grabbing the todos from local storage.

https://codesandbox.io/s/eloquent-babycat-z86dts?file=/src/App.js

  • Related