Use LocalStorage as a context value hydration error. Next.js 13
Answered
Williamson's Sapsucker posted this in #help-forum
Williamson's SapsuckerOP
I am trying to use user default settings from localStorage to initialized context provider value or use program default otherwise. thus if no data in localStoriage. I have tried several and it's given me errors
1. I first tried by checking
2. I tried this using custom hooks and it works but server complains localStorage not defined
Any help ?
1. I first tried by checking
typeof window !== 'undefined' in useEffect and I got hydration error 2. I tried this using custom hooks and it works but server complains localStorage not defined
import { useEffect, useState } from 'react';
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const storedValue = localStorage.getItem(key);
return storedValue ? JSON.parse(storedValue) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}Any help ?
Answered by aardani
you can either:
1. declare the setter in useEffect []
2. use dynamic() to skip SSR and load on browser
1. declare the setter in useEffect []
2. use dynamic() to skip SSR and load on browser
30 Replies
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(initialValue);
useEffect(() => {
const storedValue = localStorage.getItem(key);
setValue(storedValue ? JSON.parse(storedValue) : initialValue);
}, [key, initialValue]);
const setLocalStorageValue = useCallback(v => {
localStorage.setItem(key, JSON.stringify(v));
setValue(v);
}, [key]);
return [value, setLocalStorageValue];
}To make this aware of other usages of
useLocalStorage with the same key, you should probably use a BroadcastChannel, if necessary.@Somebody js
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(initialValue);
useEffect(() => {
const storedValue = localStorage.getItem(key);
setValue(storedValue ? JSON.parse(storedValue) : initialValue);
}, [key, initialValue]);
const setLocalStorageValue = useCallback(v => {
localStorage.setItem(key, JSON.stringify(v));
setValue(v);
}, [key]);
return [value, setLocalStorageValue];
}
Williamson's SapsuckerOP
thank you very much, i have tried the code above and is still given me hydration error.
That's not possible unless your initialValue differs on client/server.
Williamson's SapsuckerOP
I will snap the code here. What it dose is, it first load localStorage data. if it found it it pass to a context for page laod . if not it uses the program default values to laod the page
Williamson's SapsuckerOP
here is the provider it initial data
custom hook
@Williamson's Sapsucker custom hook
As
storedValue is const, you will run into an error on line 11 here. Though, since useEffect runs after hydration, you will only have that issue once your hydration error is fixed.Can you show the consumer of the context? The DesktopNav component that throws the error.
Williamson's SapsuckerOP
ok
@Williamson's Sapsucker here is the provider it initial data
What's the full line 25 here?
Williamson's SapsuckerOP
is a react icon
it use to expand or collpase the nav
No, in the DashboardProvider
Williamson's SapsuckerOP
there is button in the settings that allow user to hide or display nav, so line 25 listen and update the nav component
I have been able to solve the hydration error this simple trick;
@Williamson's Sapsucker I am trying to use user default settings from localStorage to initialized context provider value or use program default otherwise. thus if no data in localStoriage. I have tried several and it's given me errors
1. I first tried by checking ` typeof window !== 'undefined' ` in useEffect and I got ||hydration error ||
2. I tried this using custom hooks and it works but server complains localStorage not defined
`import { useEffect, useState } from 'react';
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const storedValue = localStorage.getItem(key);
return storedValue ? JSON.parse(storedValue) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
`
Any help ?
you can't use web api in initial value of use state as it is run in the server to give the initial HTML
you can either:
1. declare the setter in useEffect []
2. use dynamic() to skip SSR and load on browser
1. declare the setter in useEffect []
2. use dynamic() to skip SSR and load on browser
Answer
in my case, I fetch the localStorage on click before navigating to another page and add the localstorage value in the Link href
Williamson's SapsuckerOP
const [mount, setMount] = useState(false)
useEffect(()=>{
setMount(true)
})
if(!mount){
return <></>
}@aardani you can't use web api in initial value of use state as it is run in the server to give the initial HTML
Williamson's SapsuckerOP
okay
so get the localstorage value before router.push then when you click it, supply the destination link with the localstorage value
that way you don't even need usestate or useEffect at all to load initial selected value
Williamson's SapsuckerOP
Let me try that and update you. thank you
Williamson's SapsuckerOP
dynamic() also works well. Thank you all for your time and effort. I really appreciate that ðŸ‘
Checkered Giant
Hi all, I'm using a Next.js app in an
app directory and I need a solution for an error that occurs when I initialize easy-peasy. Can someone please provide me with a solution for this issue? https://github.com/dharmveer97/local-storage-easy-peasyWilliamson's SapsuckerOP
what were try to do that brought this error?