Changelog - 2026-11-04
useStoredState updaters compose, and the sign-out order is documented
Bug FixIn one line. setValue((previous) => ...) of useStoredState ran the updater on the value of the last render, so two updaters in one tick lost the first update. It now runs on the value at the moment you call it, as React's own setState(updater) does.
tsx
import { useStoredState } from '@venizia/ardor';
export function Counter() {
const { value, setValue } = useStoredState({ key: '@app/store/count', defaultValue: 0 });
const addTwo = () => {
setValue((previous: number) => previous + 1);
setValue((previous: number) => previous + 1);
// stores value + 2; it stored value + 1 before
};
return <button onClick={addTwo}>{value}</button>;
}What changed
- An updater sees the current value. That is the stored value, so it includes a write made a moment ago by another call, another hook on the same key, or code outside React. After a write or a removal that the storage refused, it is the value the hook keeps.
setValuekeeps its identity when the value changes, as long asdefaultValueandcodecare stable, because it no longer depends on the last render's value.- A plain value is unchanged.
setValue(10)stores 10, and an updater called after it builds on 10. - Sign out without a flash. The
useStoredStatereference now says how to remove session keys at sign-out.remove()tells every hook mounted on the key, so remove the keys after the protected tree has unmounted, and gate the effects that write the store on the signed-in state, or a still-mounted effect can write defaults back. There is nosilentoption, because the browser tells other tabs on its own and no option can stop that.
Who is affected
- An app that calls
setValuewith an updater more than once in one tick, or on two hooks of one key. Those updates now all apply. Code that worked around the lost update (a ref holding the latest value, a single combined updater) can stay or be removed. - An effect that calls
setValue((current) => current + 1). In React StrictMode in development the effect runs twice, so the value now goes up by 2, as it does with React's ownsetState. Production runs it once. - An app that writes the key without telling the hook, after the storage refused a write of the hook. The hook builds an updater on the value it keeps and does not see that write until the storage next notifies it (a
BrowserStoragewrite or astorageevent). See Hooks. - All other apps. No action needed.
See Hooks.