--- title: React usePersistedState hook tags: hooks,state,effect author: chalarangelo cover: red-berries firstSeen: 2020-11-29T14:16:36+02:00 lastUpdated: 2021-10-13T19:29:39+02:00 --- Returns a stateful value, persisted in `localStorage`, and a function to update it. - Use the `useState()` hook to initialize the `value` to `defaultValue`. - Use the `useRef()` hook to create a ref that will hold the `name` of the value in `Window.localStorage`. - Use 3 instances of the `useEffect()` hook for initialization, `value` change and `name` change respectively. - When the component is first mounted, use `Storage.getItem()` to update `value` if there's a stored value or `Storage.setItem()` to persist the current value. - When `value` is updated, use `Storage.setItem()` to store the new value. - When `name` is updated, use `Storage.setItem()` to create the new key, update the `nameRef` and use `Storage.removeItem()` to remove the previous key from `Window.localStorage`. - **Note:** The hook is meant for use with primitive values (i.e. not objects) and doesn't account for changes to `Window.localStorage` due to other code. Both of these issues can be easily handled (e.g. JSON serialization and handling the `'storage'` event). ```jsx const usePersistedState = (name, defaultValue) => { const [value, setValue] = React.useState(defaultValue); const nameRef = React.useRef(name); React.useEffect(() => { try { const storedValue = localStorage.getItem(name); if (storedValue !== null) setValue(storedValue); else localStorage.setItem(name, defaultValue); } catch { setValue(defaultValue); } }, []); React.useEffect(() => { try { localStorage.setItem(nameRef.current, value); } catch {} }, [value]); React.useEffect(() => { const lastName = nameRef.current; if (name !== lastName) { try { localStorage.setItem(name, value); nameRef.current = name; localStorage.removeItem(lastName); } catch {} } }, [name]); return [value, setValue]; }; ``` ```jsx const MyComponent = ({ name }) => { const [val, setVal] = usePersistedState(name, 10); return ( { setVal(e.target.value); }} /> ); }; const MyApp = () => { const [name, setName] = React.useState('my-value'); return ( <> { setName(e.target.value); }} /> ); }; ReactDOM.createRoot(document.getElementById('root')).render( ); ```