useLocalStorage()
Persist the state with local storage so that it remains after a page refresh. This can be useful for a dark theme or to record session information.
This hook is used in the same way as useState except that you must pass the storage key in the 1st parameter.
If the window object is not present (as in SSR), useLocalStorage()
will return the default value.
The Hook
1import { useEffect, useState } from 'react'23function useLocalStorage<T>(4 key: string,5 initialValue: T,6): [T, (value: T) => void] {7 // Get from local storage then8 // parse stored json or return initialValue9 const readValue = () => {10 // Prevent build error "window is undefined" but keep keep working11 if (typeof window === 'undefined') {12 return initialValue13 }1415 try {16 const item = window.localStorage.getItem(key)17 return item ? JSON.parse(item) : initialValue18 } catch (error) {19 console.warn(`Error reading localStorage key “${key}”:`, error)20 return initialValue21 }22 }2324 // State to store our value25 // Pass initial state function to useState so logic is only executed once26 const [storedValue, setStoredValue] = useState<T>(readValue)2728 // Return a wrapped version of useState's setter function that ...29 // ... persists the new value to localStorage.30 const setValue = (value: T) => {31 // Prevent build error "window is undefined" but keeps working32 if (typeof window == 'undefined') {33 console.warn(34 `Tried setting localStorage key “${key}” even though environment is not a client`,35 )36 }3738 try {39 // Allow value to be a function so we have the same API as useState40 const newValue = value instanceof Function ? value(storedValue) : value4142 // Save to local storage43 window.localStorage.setItem(key, JSON.stringify(newValue))4445 // Save state46 setStoredValue(newValue)4748 // We dispatch a custom event so every useLocalStorage hook are notified49 window.dispatchEvent(new Event('local-storage'))50 } catch (error) {51 console.warn(`Error setting localStorage key “${key}”:`, error)52 }53 }5455 useEffect(() => {56 setStoredValue(readValue())57 // eslint-disable-next-line react-hooks/exhaustive-deps58 }, [])5960 useEffect(() => {61 const handleStorageChange = () => {62 setStoredValue(readValue())63 }6465 // this only works for other documents, not the current one66 window.addEventListener('storage', handleStorageChange)6768 // this is a custom event, triggered in writeValueToLocalStorage69 window.addEventListener('local-storage', handleStorageChange)7071 return () => {72 window.removeEventListener('storage', handleStorageChange)73 window.removeEventListener('local-storage', handleStorageChange)74 }75 // eslint-disable-next-line react-hooks/exhaustive-deps76 }, [])7778 return [storedValue, setValue]79}8081export default useLocalStorage
Usage
1import React from 'react'23import useLocalStorage from './useLocalStorage'45// Usage6export default function Component() {7 const [isDarkTheme, setDarkTheme] = useLocalStorage('darkTheme', true)89 const toggleTheme = () => {10 setDarkTheme(!isDarkTheme)11 }1213 return (14 <button onClick={toggleTheme}>15 {`The current theme is ${isDarkTheme ? `dark` : `light`}`}16 </button>17 )18}
Created:
11 months ago