# `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 ```tsx import { useNRPN } from "@suaveplan/react-midi"; function ParamPanel() { const change = useNRPN("first"); if (!change) return
Move a knob…
; return (NRPN ({change.paramHigh}.{change.paramLow}) → {change.value}
); } ``` ## Usage: Advanced ```tsx function NRPNLog() { const change = useNRPN("first"); const log = useRef{JSON.stringify(log.current, null, 2)};
}
```
## 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.