Search code examples
reactjsreact-hooksnext.jsstatic-site-generation

Why useLocalStorage does not work with Next.js?


This will raise an Error: Hydration failed because the initial UI does not match what was rendered on the server. error:

const [selectedOrganizationShortId, setSelectedOrganizationShortId] =
useLocalStorage<string>('teamId', undefined)

This will not:

const [selectedOrganizationShortId, setSelectedOrganizationShortId] =
useState<string>(undefined)
const [selectedProgramId, saveSelectedProgramId] = useState<
string | undefined
>(undefined)

though both does the same. I would use useLocalStorage as it is handy convenience solution, but seems it is not compatible with Next.js.

useLocalStorage is used from here: https://usehooks-ts.com/react-hook/use-local-storage


Solution

  • This works for me:

    import { useEffect, useState, Dispatch, SetStateAction } from 'react'
    
    type SetValue<T> = Dispatch<SetStateAction<T>>
    
    export default function useLocalStorage<T>(
        key: string,
        fallbackValue: T
    ): [T, SetValue<T>] {
        const [value, setValue] = useState()
        useEffect(() => {
            const stored = localStorage.getItem(key)
            if (!stored) {
                return
            }
            setValue(stored ? JSON.parse(stored) : fallbackValue)
        }, [fallbackValue, key])
    
        useEffect(() => {
            if (!value) {
                return
            }
            localStorage.setItem(key, JSON.stringify(value))
        }, [key, value])
    
        return [value, setValue]
    }
    

    And calling like this:

    const [selectedOrganizationShortId, setSelectedOrganizationShortId] =
            useLocalStorage<string>(
                'teamId',
                auth.userDTO?.organizations
                    ? Object.keys(auth.userDTO?.organizations)[0]
                    : ''