first commit
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# `hooks/use-chain-plugin`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`useChainPlugin(trackId, slotIndex)` returns the `AudioFxPlugin`
|
||||
currently occupying a specific slot in a track's `PluginChain`, or
|
||||
`undefined` if the slot is empty. It is the per-slot view of
|
||||
`usePluginChain` — useful for rendering a single
|
||||
`<PluginSlot plugin={...} />` without re-rendering on every other
|
||||
slot's parameter change. The hook re-renders only when chain
|
||||
composition changes affect the targeted slot (`plugin-added`,
|
||||
`plugin-removed`, `plugin-moved`, `plugin-replaced`).
|
||||
|
||||
## Features
|
||||
|
||||
- `useSyncExternalStore`-based subscription to four chain events.
|
||||
- Returns `undefined` for out-of-range or empty slots — render-safe.
|
||||
- Stable behaviour across React 18+ concurrent rendering.
|
||||
- Listener cleanup on unmount.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```tsx
|
||||
import { useChainPlugin } from "@suaveplan/react-audio";
|
||||
|
||||
function SlotName({ trackId, slot }: { trackId: string; slot: number }) {
|
||||
const plugin = useChainPlugin(trackId, slot);
|
||||
return <span>{plugin?.metadata.name ?? "(empty)"}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```tsx
|
||||
import { useChainPlugin, useParameter } from "@suaveplan/react-audio";
|
||||
|
||||
function SlotGain({ trackId, slot }: { trackId: string; slot: number }) {
|
||||
const plugin = useChainPlugin(trackId, slot);
|
||||
if (plugin === undefined) return null;
|
||||
return <ParameterKnob plugin={plugin} paramId="gain" />;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `useChainPlugin(trackId, slotIndex): AudioFxPlugin | undefined`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The hook subscribes to four chain events but reads only
|
||||
`chain.plugins[slotIndex]` in its snapshot, so React re-renders the
|
||||
consumer when (and only when) one of those events fires. Reading by
|
||||
index is O(1) on the chain's internal array. `useSyncExternalStore`
|
||||
returns the same plugin reference for the same slot across re-renders
|
||||
when nothing about that slot changed, so downstream `useMemo` /
|
||||
`useEffect` keyed on the plugin behave correctly. The hook ignores
|
||||
`parameter-changed` and `bypass-changed` events because they don't
|
||||
move the slot's plugin — for per-parameter subscriptions a child
|
||||
should use `useParameter`. The list of subscribed events therefore
|
||||
captures the smallest set of changes that could affect the value
|
||||
returned, keeping per-slot re-renders proportional to actual chain
|
||||
edits.
|
||||
Reference in New Issue
Block a user