Sync component state with local storage

~/leohuynh.dev/gists/sync-react-component-state-with-local-storage

Simple custom hook to synchronize component state with local storage.

import { useState, useEffect } from 'react'

export function useLocalStorageState<T = { [key: string]: any }>(key: string, defaultValue?: T) {

let [state, setState] = useState<T>(() => {

let storage = localStorage.getItem(key)

if (storage) {

return JSON.parse(storage)

}

return defaultValue || {}

})

useEffect(() => {

localStorage.setItem(key, JSON.stringify(state))

}, [state])

// Using `as const` to ensure the type of the returned array is correct

return [state, setState] as const

}

In some cases, you might need to check for browser environment, cause local storage is available only in the client side.

import { useState, useEffect } from 'react'

let isBrowser = typeof window !== 'undefined' // Check for browser/client environment

export function useLocalStorageState<T = { [key: string]: any }>(key: string, defaultValue?: T) {

let [state, setState] = useState<T>(() => {

if (isBrowser) {

let storage = localStorage.getItem(key)

if (storage) {

return JSON.parse(storage)

}

}

return defaultValue || {}

})

useEffect(() => {

localStorage.setItem(key, JSON.stringify(state))

}, [state])

return [state, setState] as const

}

Usage

A simple example of using the hook to synchronize component state with local storage is shown below:

function ThemeSwitcher() {

let [theme, setTheme] = useLocalStorageState<'dark' | 'light'>('theme', 'light')

return (

<select onChange={ev => setTheme(ev.target.value)}>

<option value="dark">Dark</option>

<option value="light">Light</option>

</select>

)

}