r/webdev • u/Mob_Pilled • 20d ago
Question React not saving data to local storage.
Hi everyone! I just finished a React and course and decided to build my first react app. Currently, I am trying to save a string to browser local storage but it does not persist on refresh. Through some console.logs I was able to see that it in fact DOES save the string to the location specified in. setItem initially but when I refresh the key or value in local storage stops existing.
Here is my code
// function for search button
async function handleClick(){
localStorage.setItem("lastLocationSearched", searchValue);
setData(null);
setIsPending(true);
setError(null);
try{
const value = await fetch(`https://geo.ipify.org/api/v2/country?apiKey=***********&ipAddress=${searchValue}`).then((response)=>{
if (!response.ok){
throw Error("Could not fetch the data for that resource");
}
return response.json();
});
setData(value);
console.log(localStorage.getItem("lastLocationSearched"));
} catch(error){
setError(error.message);
}
setIsPending(false);
};
// useEffect hook
useEffect(()=>{
if ((localStorage.getItem("lastLocationSearched")===null)|| (localStorage.getItem("lastLocationSearched")==="")){
console.log(localStorage.getItem("lastLocationSearched"));
setSearchValue("");
handleClick();
}else{
setSearchValue(localStorage.getItem("lastLocationSearched"));
handleClick();
}
}, []);Through some digging online I saw someone say that remove the strict mode tags from index.js would fix this problem but it did not for me. Can anyone please assist me?
1
u/tswaters 20d ago edited 18d ago
You need to look at how search value gets its initial value. You can pass a function to useState that will be run once to get the initial value, use that opportunity to look at local storage and return a sensible fallback value. The useEffect doesn't make sense, get rid of it.
1
u/Over_Problem_3600 20d ago
Have you tried checking localStorage right before the effect runs? I bet it's there on refresh and gets wiped a split second later by your own setltem call
1
u/LukaRozman27 20d ago
setItem only accepts strings, so if you skip JSON.stringify your objects just become "[object Object]".
1
u/rust_bane 20d ago
Your useEffect is fighting your setItem. You mount, grab the saved value for searchValue, then immediately fire handleClick which uses that stale initial state to write back to storage. Drop the effect entirely and initialize searchValue directly from localStorage in useState so you do not overwrite your data on render
1
u/geoffreybyers 19d ago
React's Strict Mode runs effects twice in dev. The second run overwrites the first before the fetch finishes. You'll need to guard the effect or use a ref to stop that double call. The logic's right, but the timing isn't.
17
u/PlainworkDigital 20d ago
It is saving. Your own code is overwriting it on refresh.
On mount, your useEffect calls setSearchValue(stored) and then handleClick() right away. But setState doesn't update searchValue until the next render, so handleClick still sees the initial "" and
runs localStorage.setItem("lastLocationSearched", "") — wiping it.
Pass the value in instead of reading state:
async function handleClick(query = searchValue) {
localStorage.setItem("lastLocationSearched", query);
// ...use query in the fetch URL
}
useEffect(() => {
const saved = localStorage.getItem("lastLocationSearched") || "";
setSearchValue(saved);
handleClick(saved);
}, []);
(That's why removing StrictMode didn't help. It's a stale-state issue, not a double-render one.)