Write a useLocalStorageState hook that saves state as JSON
Write useLocalStorageState(key, initial). It works like useState, returning [value, setValue], but the value is saved in localStorage under key, so a cart survives a reload.
Read the saved value with JSON.parse when the component first renders, and don't read storage again on later renders. If nothing is saved, start with initial. If what's saved isn't valid JSON, don't crash: start with initial. A saved 0, false, or "" is a real value, not a missing one.
setValue takes a value or an updater, setValue((current) => next), and saves the result with JSON.stringify. Two updaters in the same event both apply.
If key changes, switch to what's saved under the new key (or initial), and don't copy the old key's value into it.
function Cart({ userId }) {
const [teas, setTeas] = useLocalStorageState("cart:" + userId, []);
return (
<>
<p>{teas.length} in the cart</p>
<button onClick={() => setTeas((current) => [...current, "Sencha"])}>Add Sencha</button>
</>
);
}
import { useCallback, useEffect, useState } from "react";
export function useLocalStorageState(key, initial) {
const [value, setValue] = useState(initial);
// Start from what's saved under key, and save every change as JSON.
return [value, setValue];
}
- starts with initial when nothing is saved
- starts with the saved JSON
- falls back to initial when the saved text isn't JSON
- keeps a saved 0 or false
- saves each new value as JSON
- two updaters in one event both apply
- reads storage once, not on every render
- switches to the new key's value when the key changes
- a cart is still there after it's unmounted and rendered again
The answer
Write it yourself first. Then compare it with a reference solution and the checks it passes.
Checking your sign-in…