Reputation: 37
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
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
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
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