2.4 KiB
hooks/use-provider-state
(no submodules)
Purpose
Internal helpers shared across every public hook. They centralise the
two structured-error throws every engine-dependent hook must perform:
REACT_AUDIO.NO_PROVIDER when the consumer renders outside an
<AudioProvider> ancestor, and REACT_AUDIO.PROVIDER_PENDING when
the engine has not yet finished its async init. Keeping the throw
logic in one file means there is exactly one place to audit the error
contract.
Features
useProviderStateOrThrow()— returns the resolvedProviderStateor throws.useAudioContextOrThrow()— returns the rawAudioContextValue(without the pending check) for hooks likeuseEngineStatethat need to report the lifecycle phase rather than throw on it.
Usage: Basic
import { useProviderStateOrThrow } from "@suaveplan/react-audio";
function MyHook() {
const state = useProviderStateOrThrow();
return state.transport;
}
Usage: Advanced
import { useAudioContextOrThrow } from "@suaveplan/react-audio";
function useReadyOrLoading(): "ready" | "loading" {
const ctx = useAudioContextOrThrow();
return ctx.engineState === "ready" ? "ready" : "loading";
}
API Reference
useProviderStateOrThrow(): ProviderState— throwsREACT_AUDIO.NO_PROVIDERoutside provider; throwsREACT_AUDIO.PROVIDER_PENDINGwhile engine init is pending.useAudioContextOrThrow(): AudioContextValue— throwsREACT_AUDIO.NO_PROVIDERoutside provider.
Implementation Notes
useContext returns null as the "no provider" sentinel because the
context's default value is null. The two helpers use a single
discriminator check (ctx === null) for that path so the throw site
is canonical. useProviderStateOrThrow additionally checks for
ctx.state === null (the async init window) and throws
PROVIDER_PENDING so engine-dependent hooks fail fast — consumers
typically gate on useEngineState() === 'ready' before rendering
those hooks' subtrees. The split into two helpers exists so
useEngineState itself can read the phase without throwing on it —
otherwise the consumer would have no way to discover "we're still
initialising" without crashing the component tree. Both helpers
register exactly one React hook (useContext) so any downstream hook
can register additional useCallback / useSyncExternalStore calls
unconditionally and stay compliant with the Rules of Hooks.