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

2.0 KiB

hooks/use-nrpn

(no submodules)

Purpose

useNRPN(selector) wraps the universal NRPN reducer from the midi-contract module and exposes the consolidated NRPNChange as React state. NRPN ("Non-Registered Parameter Number") edits arrive over the wire as a four-CC dance — CC 99 (param MSB), CC 98 (param LSB), CC 6 (data MSB), CC 38 (data LSB) — and consumers usually want a single React-level event per completed dance rather than four intermediate controlChange events. The hook performs that fold internally and re-renders once per consolidated change.

The reducer is owned per port: when the underlying input identity changes (plug/unplug, selector switch) the reducer is reset, so a half-completed dance from a previous device does not leak into the new one.

Features

  • Folds CC 99/98/6/38 into one NRPNChange per dance.
  • Per-port reducer — no cross-device interference.
  • Resets internal state on port identity change.
  • Returns null until the first completed dance.

Usage: Basic

import { useNRPN } from "@suaveplan/react-midi";

function ParamPanel() {
    const change = useNRPN("first");
    if (!change) return <p>Move a knob…</p>;
    return (
        <p>
            NRPN ({change.paramHigh}.{change.paramLow}) → {change.value}
        </p>
    );
}

Usage: Advanced

function NRPNLog() {
    const change = useNRPN("first");
    const log = useRef<NRPNChange[]>([]);
    useEffect(() => {
        if (change !== null) log.current.push(change);
    }, [change]);
    return <pre>{JSON.stringify(log.current, null, 2)}</pre>;
}

API Reference

  • useNRPN(selector: string | "first"): NRPNChange | null

Implementation Notes

The hook keeps the reducer in a useRef (rather than a useMemo or useState) because the reducer is conceptually an external store attached to the lifetime of the port subscription, not a render output. When the port becomes null the ref is cleared so a fresh port gets a fresh reducer.