State
useLocalStorageWithExpiry
Persisted state with a TTL.
Demo
live · imported from hookli
- stored value
- —
- expires in
- —
nothing stored yet
import { useLocalStorageWithExpiry } from "hookli";
export function Demo() {
const { value, setStoredValue } = useLocalStorageWithExpiry(
"draft",
"",
10_000,
);
return (
<div>
<button onClick={() => setStoredValue("hello")}>Save for 10s</button>
<p>{value === null ? "Expired" : value || "Nothing stored"}</p>
</div>
);
}Usage
import { useLocalStorageWithExpiry } from "hookli";
export function Demo() {
const { value, setStoredValue } = useLocalStorageWithExpiry(
"draft",
"",
10_000,
);
return (
<div>
<button onClick={() => setStoredValue("hello")}>Save for 10s</button>
<p>{value === null ? "Expired" : value || "Nothing stored"}</p>
</div>
);
}API
useLocalStorageWithExpiry<T>(key: string, initialValue: T, expiryMs: number): { value: T | null; setStoredValue: (value: T) => void }Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| key | string | — | The localStorage key to read and write. |
| initialValue | T | — | Value used before hydration and when nothing is stored under the key. |
| expiryMs | number | — | Time-to-live in milliseconds. Every write stores the value with a fresh expiry timestamp. |
Returns
| Name | Type | Description |
|---|---|---|
| value | T | null | The stored value, or null once the item has expired. Expiry is checked when the hook reads — on mount or key change — at which point the item is removed. |
| setStoredValue | (value: T) => void | Persists the value to localStorage with a new expiry of now + expiryMs. |
Hook
The implementation, straight from hookli. Copy it, or install the package.
import { useEffect, useState } from "react";
export const useLocalStorageWithExpiry = <T>(
key: string,
initialValue: T,
expiryMs: number,
) => {
const read = (): T | null => {
if (typeof window === "undefined") return initialValue;
const raw = window.localStorage.getItem(key);
if (!raw) return initialValue;
try {
const item = JSON.parse(raw);
if (
item &&
typeof item.expiry === "number" &&
Date.now() > item.expiry
) {
window.localStorage.removeItem(key);
return null;
}
return item.value;
} catch {
return initialValue;
}
};
const [value, setValue] = useState<T | null>(initialValue);
useEffect(() => {
setValue(read());
}, [key]);
const setStoredValue = (newValue: T) => {
setValue(newValue);
if (typeof window === "undefined") return;
const item = { value: newValue, expiry: Date.now() + expiryMs };
window.localStorage.setItem(key, JSON.stringify(item));
};
return { value, setStoredValue };
};