Skip to content

Storage and event subscriptions ​

These hooks adapt shared external resources to a component. Keep KeyStorage and bus instances stable, and let their creator own destruction. Component unmount unsubscribes listeners; it does not destroy shared storage or the bus.

APIInput / return / default
useKeyStorage(storage)Returns [T | null, set(T), remove()]; missing storage is null.
useKeyStorage(storage, defaultValue)Returns [T, set(T), remove()]; fallback is read when stored value is null and is not automatically persisted.
useImmerKeyStorage(storage, defaultValue?)Same tuple, but setter accepts an Immer draft updater; returning null removes the key.
useEventSubscription({ bus, handler })Automatically subscribes under handler.name; returns boolean-valued subscribe/unsubscribe functions. Cleanup calls off(handler.name) only if that on succeeded.

Storage uses useSyncExternalStore, caches deep-equal snapshots, and resubscribes when the storage instance changes. The server snapshot is defaultValue ?? null, so the server render does not read storage: on the server and during hydration the hook renders the default (so useSecurity and SecurityProvider start unauthenticated), then the stored value. Client-only rendering reads storage from the first render. Serialization/storage exceptions propagate; these hooks do not convert them into a Promise error state. The Immer updater reads the current stored value when invoked, so successive updates do not rely on a render's stale snapshot. Retained callbacks continue to target the storage they captured.

Event handlers have names; use a distinct name per subscriber. Duplicate names can reject registration, which logs a warning; cleanup then leaves the name alone, so the other subscriber's handler stays registered. The hook subscribes once per bus and handler name/order/once, and each event calls the latest handle, so an inline handler object does not resubscribe on every render; changing the bus, name, order or once does. The bus controls handler failure propagation and delivery order; this hook neither changes those policies nor awaits delivery on behalf of publishers.

Complete example ​

tsx
import { KeyStorage, InMemoryStorage } from '@ahoo-wang/fetcher-storage';
import { useImmerKeyStorage } from '@ahoo-wang/fetcher-react';
const preferences = new KeyStorage<{ count: number }>({
  key: 'preferences',
  storage: new InMemoryStorage(),
});
export function Counter() {
  const [value, update, remove] = useImmerKeyStorage(preferences, { count: 0 });
  return (
    <section>
      <button
        onClick={() =>
          update(draft => {
            draft.count += 1;
          })
        }
      >
        {value.count}
      </button>
      <button onClick={remove}>Reset stored value</button>
    </section>
  );
}

Public signatures and types ​

These signatures follow declarations reachable from the current root entry. ? marks optional input; generics/interfaces only constrain compile-time types. Locate inherited and related types through the symbol index. Runtime defaults and failure behavior are described above.

useKeyStorage ​

ts
export function useKeyStorage<T>(
  keyStorage: KeyStorage<T>,
): [T | null, (value: T) => void, () => void];

packages/react/src/storage/useKeyStorage.ts:19

ts
export function useKeyStorage<T>(
  keyStorage: KeyStorage<T>,
  defaultValue: T,
): [T, (value: T) => void, () => void];

packages/react/src/storage/useKeyStorage.ts:23

useImmerKeyStorage ​

ts
export function useImmerKeyStorage<T>(
  keyStorage: KeyStorage<T>,
): [
  T | null,
  (updater: (draft: T | null) => T | null | void) => void,
  () => void,
];

packages/react/src/storage/useImmerKeyStorage.ts:23

ts
export function useImmerKeyStorage<T>(
  keyStorage: KeyStorage<T>,
  defaultValue: T,
): [T, (updater: (draft: T) => T | null | void) => void, () => void];

packages/react/src/storage/useImmerKeyStorage.ts:31

useEventSubscription ​

ts
export function useEventSubscription<EVENT = unknown>(
  options: UseEventSubscriptionOptions<EVENT>,
): UseEventSubscriptionReturn;

packages/react/src/eventbus/useEventSubscription.ts:94

UseEventSubscriptionOptions ​

ts
export interface UseEventSubscriptionOptions<EVENT> {
  bus: TypedEventBus<EVENT>;
  handler: EventHandler<EVENT>;
}

packages/react/src/eventbus/useEventSubscription.ts:22

UseEventSubscriptionReturn ​

ts
export interface UseEventSubscriptionReturn {
  subscribe: () => boolean;
  unsubscribe: () => boolean;
}

packages/react/src/eventbus/useEventSubscription.ts:36

Fetcher hooks · Promise and query state · API hook factories · Debounced execution · Security hooks and route guards · Latest and stable values

Released under the Apache License 2.0.