UNPKG

@blac/react

Version:

React bindings for BlaC — useBloc hook with automatic re-render optimization

75 lines (74 loc) 3.16 kB
import type { ExtractArgs, ExtractState, InstanceReadonlyState, StateContainerConstructor } from '@blac/core'; import type { RefObject } from 'react'; /** * Conditional `args` field: * - When the bloc uses the default `void` Args: args is forbidden (type `never`). * - When the bloc declares Args: args is optional (may be inherited from a * `BlocProvider` ancestor at runtime; omitting it resolves to the provider * args or the default key). */ type ArgsOption<T extends StateContainerConstructor> = ExtractArgs<T> extends void ? { args?: never; } : { args?: ExtractArgs<T>; }; /** * Configuration options for {@link useBloc}. * * @template TBloc - The state container constructor type * * @remarks * Instance identity is derived entirely from `args`. For a per-mount private * instance, pass a stable unique object: `{ args: { _id: useId() } }`, or set * `isolated: true` (equivalent, no `useId()` needed). * * To re-render on a fixed set of values rather than on auto-tracked reads, pass * `select` — it returns a tuple/array that is compared per-index via * `Object.is`. */ export type UseBlocOptions<TBloc extends StateContainerConstructor> = ArgsOption<TBloc> & { /** * Per-consumer re-render selector. When provided, the hook re-renders * only when the returned array's elements change (Object.is per index). * When omitted, auto-tracking is used: any state path read during the * render is observed, and the hook re-renders when any of those paths * change. * * Keep the selector referentially stable across renders (e.g. via * `useCallback`) — passing a fresh function each render forces the * subscription to re-key, which the underlying channel treats as a new * consumer. */ select?: (state: ExtractState<TBloc>, bloc: InstanceReadonlyState<TBloc>) => unknown[]; /** Callback invoked when this consumer mounts. */ onMount?: (bloc: InstanceType<TBloc>) => void; /** * Callback invoked when this consumer unmounts. Fires *before* the * registry releases its ref, so the bloc is still alive when this runs. */ onUnmount?: (bloc: InstanceType<TBloc>) => void; /** * Give this mount a private instance nobody else shares. Sugar over args * identity — it injects a stable per-mount id into `args`; there is no * separate identity mechanism. Equivalent to `static isolated = true` on the * class; both present is fine. * * Note: the injected id is visible in the `args` object passed to `init()`. */ isolated?: boolean; }; /** * Tuple return type from {@link useBloc}. * - [0] Current state value * - [1] State container instance (bloc) for calling actions * - [2] Ref object for accessing component ref (advanced use cases) * * @template TBloc - The state container constructor type */ export type UseBlocReturn<TBloc extends StateContainerConstructor, S = ExtractState<TBloc>> = [S, InstanceReadonlyState<TBloc>, RefObject<ComponentRef>]; /** * Internal ref structure for component-bloc binding. * @internal */ export type ComponentRef = Record<string, never>; export {};