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

2.3 KiB

hooks/use-midi-input

(no submodules)

Purpose

useMidiInput(selector) returns a typed MidiPortLike adapter over a single Web MIDI input. The adapter parses raw bytes into the discriminated MidiMessage union before delivering them through onMessage, so consumers never touch byte-level details. The selector is either an explicit MIDIInput.id or the literal "first" shorthand that picks whichever input the access enumerates first — useful when the host has exactly one device plugged in.

The hook returns null when access is still pending, when the selector misses (e.g. a stale id), or when there are zero inputs. This null-return shape composes cleanly with conditional rendering; consumers don't need to thread an explicit loading state.

Features

  • Two selector forms: id string or "first" literal.
  • Returns null during loading / denial / unknown id.
  • Adapter identity memoised against access + stateVersion + selector.
  • Multi-subscriber fan-out from a single Web MIDI input.

Usage: Basic

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

function NoteListener() {
    const port = useMidiInput("first");
    useEffect(() => {
        if (port === null) return;
        return port.onMessage((msg) => {
            if (msg.type === "noteOn") console.log(msg.note, msg.velocity);
        });
    }, [port]);
    return null;
}

Usage: Advanced

function PerDeviceListeners() {
    const { inputs } = useMidi();
    return (
        <>
            {inputs.map((i) => (
                <PortFan key={i.id} portId={i.id} />
            ))}
        </>
    );
}

function PortFan({ portId }: { portId: string }) {
    const port = useMidiInput(portId);
    // ... attach handlers via port.onMessage
    return null;
}

API Reference

  • useMidiInput(selector: string | "first"): MidiPortLike | null

Implementation Notes

The hook calls adaptInput inside useMemo so the adapter identity matches the underlying MIDIInput for the duration of the hook's lifetime. Because adaptInput keeps its own Set<subscriber> and the useMemo recreates the adapter when the underlying port changes (plug/unplug), any active subscription should re-bind from a useEffect keyed on [port].