Files
skills/docs/ui/react/react-audio/src/hooks/use-provider-state.md
2026-05-29 08:20:56 +01:00

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 resolved ProviderState or throws.
  • useAudioContextOrThrow() — returns the raw AudioContextValue (without the pending check) for hooks like useEngineState that 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 — throws REACT_AUDIO.NO_PROVIDER outside provider; throws REACT_AUDIO.PROVIDER_PENDING while engine init is pending.
  • useAudioContextOrThrow(): AudioContextValue — throws REACT_AUDIO.NO_PROVIDER outside 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.