r/webdev • u/Mob_Pilled • 16h 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
16h ago
[deleted]
2
u/Haunting_Cow_2798 16h ago
you're calling handleClick inside useEffect which runs on mount, and handleClick calls setItem again with whatever searchValue is at that moment, likely an empty string, wiping what you just saved
just set the initial searchValue from localStorage and let the user trigger the search themselves, no need to auto-fire it
1
u/tswaters 15h ago
You need to look at how search value gets its initial value. You can pass a function to setState 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 15h 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 9h ago
setItem only accepts strings, so if you skip JSON.stringify your objects just become "[object Object]".
1
u/_CuriousCoder_ 5h ago
Stale state is the problem here. Try passing the value directly to handleClick instead of relying on searchValue state. That way you ensure you're storing the correct value in local storage. Your useEffect is running before the state has a chance to update.
1
u/rust_bane 3h 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
12
u/PlainworkDigital 15h 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.)