mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-25 12:35:18 -05:00
54 lines
1.5 KiB
TypeScript
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,
|
|
);
|
|
}
|