@tldraw/state-react
Version:
tldraw infinite canvas SDK (react bindings for state).
8 lines (7 loc) • 3.6 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/useReactor.ts"],
"sourcesContent": ["import { EffectScheduler } from '@tldraw/state'\nimport { throttleToNextFrame } from '@tldraw/utils'\nimport { useEffect } from 'react'\n\n/**\n * A React hook that runs a side effect in response to changes in signals (reactive state).\n *\n * The effect function will automatically track any signals (atoms, computed values) that are\n * accessed during its execution. When any of those signals change, the effect will be\n * scheduled to run again on the next animation frame.\n *\n * This is useful for performing side effects (like updating the DOM, making API calls, or\n * updating external state) in response to changes in tldraw's reactive state system, while\n * keeping those effects efficiently batched and throttled.\n *\n * @example\n * ```tsx\n * import { useReactor, useEditor } from 'tldraw'\n *\n * function MyComponent() {\n * const editor = useEditor()\n *\n * // Update document title when shapes change\n * useReactor(\n * 'update title',\n * () => {\n * const shapes = editor.getCurrentPageShapes()\n * document.title = `Shapes: ${shapes.length}`\n * },\n * [editor]\n * )\n *\n * return <div>...</div>\n * }\n * ```\n *\n * @example\n * ```tsx\n * import { useReactor, useEditor } from 'tldraw'\n *\n * function SelectionAnnouncer() {\n * const editor = useEditor()\n *\n * // Announce selection changes for accessibility\n * useReactor(\n * 'announce selection',\n * () => {\n * const selectedIds = editor.getSelectedShapeIds()\n * if (selectedIds.length > 0) {\n * console.log(`Selected ${selectedIds.length} shape(s)`)\n * }\n * },\n * [editor]\n * )\n *\n * return null\n * }\n * ```\n *\n * @remarks\n * The effect is throttled to run at most once per animation frame using `requestAnimationFrame`.\n * This makes it suitable for effects that need to respond to state changes but don't need to\n * run synchronously.\n *\n * If you need the effect to run immediately without throttling, use {@link useQuickReactor} instead.\n *\n * The effect function will be re-created when any of the `deps` change, similar to React's\n * `useEffect`. The effect automatically tracks which signals it accesses, so you don't need\n * to manually specify them as dependencies.\n *\n * @param name - A debug name for the effect, useful for debugging and performance profiling.\n * @param reactFn - The effect function to run. Any signals accessed in this function will be tracked.\n * @param deps - React dependencies array. The effect will be recreated when these change. Defaults to `[]`.\n *\n * @public\n */\nexport function useReactor(name: string, reactFn: () => void, deps: undefined | any[] = []) {\n\tuseEffect(() => {\n\t\tlet cancelFn: () => void | undefined\n\t\tconst scheduler = new EffectScheduler(name, reactFn, {\n\t\t\tscheduleEffect: (cb) => {\n\t\t\t\tcancelFn = throttleToNextFrame(cb)\n\t\t\t},\n\t\t})\n\t\tscheduler.attach()\n\t\tscheduler.execute()\n\t\treturn () => {\n\t\t\tscheduler.detach()\n\t\t\tcancelFn?.()\n\t\t}\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, deps)\n}\n"],
"mappings": "AAAA,SAAS,uBAAuB;AAChC,SAAS,2BAA2B;AACpC,SAAS,iBAAiB;AA0EnB,SAAS,WAAW,MAAc,SAAqB,OAA0B,CAAC,GAAG;AAC3F,YAAU,MAAM;AACf,QAAI;AACJ,UAAM,YAAY,IAAI,gBAAgB,MAAM,SAAS;AAAA,MACpD,gBAAgB,CAAC,OAAO;AACvB,mBAAW,oBAAoB,EAAE;AAAA,MAClC;AAAA,IACD,CAAC;AACD,cAAU,OAAO;AACjB,cAAU,QAAQ;AAClB,WAAO,MAAM;AACZ,gBAAU,OAAO;AACjB,iBAAW;AAAA,IACZ;AAAA,EAED,GAAG,IAAI;AACR;",
"names": []
}