Files
2026-08-05 18:16:24 +03:00

54 lines
1.5 KiB
TypeScript

import * as React from "react";
import type {
PersistedDefinition,
PersistedMapDefinition,
} from "./persisted-state";
import * as PersistedState from "./persisted-state";
const SERVER_MAP_SNAPSHOT: Record<string, never> = {};
/**
* Typed React state backed by a persisted definition. The value stays in sync
* across components and browser tabs; the setter accepts a value or an updater.
*/
export function usePersistedState<T>(
definition: PersistedDefinition<T>,
): [T, (next: T | ((previous: T) => T)) => void] {
const subscribeToDefinition = React.useCallback(
(listener: () => void) => PersistedState.subscribe(definition, listener),
[definition],
);
const value = React.useSyncExternalStore(
subscribeToDefinition,
() => PersistedState.read(definition),
() => definition.default,
);
const setValue = (next: T | ((previous: T) => T)) => {
PersistedState.write(
definition,
typeof next === "function"
? (next as (previous: T) => T)(PersistedState.read(definition))
: next,
);
};
return [value, setValue];
}
/** Read-only React view of a persisted map definition; write entries via `PersistedState.writeMapEntry`. */
export function usePersistedMapState<T>(
definition: PersistedMapDefinition<T>,
): Record<string, T> {
const subscribeToDefinition = React.useCallback(
(listener: () => void) => PersistedState.subscribeMap(definition, listener),
[definition],
);
return React.useSyncExternalStore(
subscribeToDefinition,
() => PersistedState.readMap(definition),
() => SERVER_MAP_SNAPSHOT,
);
}