2.4 KiB
hooks/use-timeline
(no submodules)
Purpose
useTimeline() returns the provider's single TimelineEngine
instance, the canonical owner of timeline state — tracks, clips,
selection, loop region, master volume, undo/redo. The engine exposes
its own typed event surface (engine.on(event, listener)); consumers
who want to subscribe to engine events should pair this hook with
useSyncExternalStore and pass engine.on(...) as the subscribe
callback. The hook itself returns the engine handle and does not
trigger re-renders on engine state changes.
Features
- Returns the
TimelineEngineinstance owned by the provider. - Stable identity across re-renders within a ready phase.
- Throws
REACT_AUDIO.NO_PROVIDERoutside<AudioProvider>. - Throws
REACT_AUDIO.PROVIDER_PENDINGduring async init.
Usage: Basic
import { useTimeline } from "@suaveplan/react-audio";
function AddTrackButton() {
const timeline = useTimeline();
return (
<button type="button" onClick={() => timeline.addTrack({ name: "New Track" })}>
Add track
</button>
);
}
Usage: Advanced
import { useSyncExternalStore } from "react";
import { useTimeline } from "@suaveplan/react-audio";
function useTrackCount(): number {
const timeline = useTimeline();
return useSyncExternalStore(
(listener) => timeline.on("trackChange", listener as never),
() => timeline.getState().tracks.length,
() => timeline.getState().tracks.length
);
}
API Reference
useTimeline(): TimelineEngine— see@suaveplan/audio-timelinefor the full engine surface.
Implementation Notes
The hook deliberately stops short of re-rendering on every engine
event. The TimelineEngine has a rich change surface and re-rendering
on every state delta would be expensive at chain scale. Consumers
choose which events they care about and pair the engine handle with
useSyncExternalStore for narrow subscriptions, paying only for the
re-renders they want. Mutator methods (addTrack, updateTrack,
removeTrack, setTempo, setMasterVolume, …) are exposed directly
on the engine handle — callers wrap them in their own callbacks when
they need referential stability across renders. For per-track state
prefer useTrack(id), which already wraps useSyncExternalStore
against the timeline's trackChange event so its subscription is
narrow by construction.