Background
I have this React hook and am trying to set the initial state to the value in local storage - if it exists.
function useLocalStorageState(
key,
defaultValue = ''
) {
const [state, setState] = React.useState(() => {
const valueInLocalStorage = window.localStorage.getItem(key)
if (valueInLocalStorage) {
return valueInLocalStorage
}
return defaultValue
})
React.useEffect(() => {
window.localStorage.setItem(key, state)
}, [key, state])
return [state, setState]
}
This does not work with Next.js because "it executes code first server-side, then client-side. The window object is only present client-side." To solve this, you can use useEffect which Next.js does not process server-side and anything inside it will be processed on the client side and thus have access to the window.
The problem
I could re-write the hook to look like this with useEffect so that has access to the window. However, when the component mounts there is a flash of unstyled content (FOUC) from the defaultValue to the value in localStorage.
function useLocalStorageState(
key,
defaultValue = ''
) {
const [state, setState] = React.useState(defaultValue)
React.useEffect(() => {
const valueInLocalStorage = window.localStorage.getItem(key)
if (valueInLocalStorage) {
setState(valueInLocalStorage)
}
}, [])
React.useEffect(() => {
window.localStorage.setItem(key, state)
}, [key, state])
return [state, setState]
}
How can I set the state within the hook to be the localStorage value but also avoid this flash of content when the page re-loads to the second state.
It might be worth mentioning I'm using this to store the user's preference on whether or not they're using dark mode.