Alice378
Alice378

Reputation: 37

Local storage is not keeping the data after page reload

I'm making in react a list of episodes that user would like to watch later (similar to todo app) , but after reloading the page data is not keeping in local storage. I'm new to react, so, please help me to understand the issue. This is my code

import React, { useState, useEffect } from "react";
import { RiCloseCircleLine } from "react-icons/ri";
import { TiEdit } from "react-icons/ti";

import { MyWatchListForm } from "./MyWatchListForm";

export const MyWatchListItem = ({
  watchLists,
  completeWatchList,
  removeWatchList,
  updateWatchList,
}) => {
  const [edit, setEdit] = useState({
    id: null,
    value: "",
  });

  const submitUpdate = (value) => {
    updateWatchList(edit.id, value);
    setEdit({
      id: null,
      value: "",
    });
  };

  useEffect(() => {
    const data = localStorage.getItem("my-watchList");

    const savedData = JSON.parse(data);
    setEdit(savedData);
  }, []);

  useEffect(() => {
    localStorage.setItem("my-watchList", JSON.stringify(watchLists));
  });

  if (edit.id) {
    return <MyWatchListForm edit={edit} onSubmit={submitUpdate} />;
  }

  return watchLists.map((watchList, index) => (
    <div className={watchList.isComplete ? "checked" : ""} key={index}>
      <div key={watchList.id} onClick={() => completeWatchList(watchList.id)}>
        {watchList.text}
      </div>
      <div>
        <RiCloseCircleLine onClick={() => removeWatchList(watchList.id)} />
        <TiEdit
          onClick={() => setEdit({ id: watchList.id, value: watchList.text })}
        />
      </div>
    </div>
  ));
};

Form that is used to get the data from:

export const MyWatchListForm = (props) => {
  const [input, setInput] = useState(props.edit ? props.edit.value : "");

  const inputRef = useRef();

  useEffect(() => {
    inputRef.current.focus();
  });

  const handleSubmit = (e) => {
    e.preventDefault();

    props.onSubmit({
      id: Math.floor(Math.random() * 10000),
      text: input,
    });
    setInput("");
  };

  
  const handleChange = (e) => {
    setInput(e.target.value);
  };

  return (
    <form
      className="w-full max-w-sm flex items-center border-b border-teal-500 py-2"
      onSubmit={handleSubmit}
    >
      {props.edit ? (
        <>
          <input
            className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
            type="text"
            value={input}
            placeholder="Update the episode"
            onChange={handleChange}
            ref={inputRef}
          ></input>
          <button>Update</button>
        </>
      ) : (
        <>
          <input
            className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
            type="text"
            value={input}
            placeholder="Add the episode"
            onChange={handleChange}
            ref={inputRef}
          ></input>
          <button>Add</button>
        </>
      )}
    </form>
  );
};

And the WatchList.js file

import React, { useState } from "react";

import { MyWatchListForm } from "./MyWatchListForm";
import { MyWatchListItem } from "./MyWatchListItem";

export const MyWatchList = () => {
  const [watchLists, setWatchLists] = useState([]);

  const addWatchList = (watchList) => {
    if (!watchList.text || /^\s*$/.test(watchList.text)) {
      return;
    }
    const newWatchList = [watchList, ...watchLists];

    setWatchLists(newWatchList);
    console.log(...watchLists);
  };

  const updateWatchList = (watchListId, newValue) => {
    if (!newValue.text || /^\s*$/.test(newValue.text)) {
      return;
    }
    setWatchLists((prev) =>
      prev.map((item) => (item.id === watchListId ? newValue : item))
    );
  };

  const removeWatchList = (id) => {
    const removeArr = [...watchLists].filter(
      (watchList) => watchList.id !== id
    );
    setWatchLists(removeArr);
  };

  const completeWatchList = (id) => {
    const updatedWatchList = watchLists.map((watchList) => {
      if (watchList.id === id) {
        watchList.isComplete = !watchList.isComplete;
      }
      return watchList;
    });
    setWatchLists(updatedWatchList);
  };
  return (
    <div>
      <h1>Watch later</h1>
      <MyWatchListForm onSubmit={addWatchList} />
      <MyWatchListItem
        watchLists={watchLists}
        completeWatchList={completeWatchList}
        removeWatchList={removeWatchList}
        updateWatchList={updateWatchList}
      />
    </div>
  );
};

Upvotes: 0

Views: 1124

Answers (3)

Alice378
Alice378

Reputation: 37

I fixed the issue by changing the initial state in MyWatchList as below:

export const MyWatchList = () => {
  const [watchLists, setWatchLists] = useState(() => {
    const data = localStorage.getItem("my-watchList");
    return data ? JSON.parse(data) : [];
  });

  useEffect(() => {
    localStorage.setItem("my-watchList", JSON.stringify(watchLists));
  }, [watchLists]);

Upvotes: 2

Mohit kumar
Mohit kumar

Reputation: 487

I think the issue with your code is this snippet:

 useEffect(() => {
    localStorage.setItem("my-watchList", JSON.stringify(watchLists));
  });

Every time the state get's updated, this useEffect runs and it replaces the content of localStorage to the values which you are getting in watchlists since you are not providing a dependancy array to the useEffect.

Upvotes: 0

M3rt
M3rt

Reputation: 388

Using the useEffect hook without a dependency array is never a good idea. It basically runs on every render. Actually, goal of the useEffect is to solve this problem. Remove your useEffect and try like this;

const submitUpdate = (value) => {
  updateWatchList(edit.id, value);
  setEdit({
    id: null,
    value: "",
  });

  localStorage.setItem("my-watchList", JSON.stringify(watchLists));

};

Upvotes: 0

Related Questions