UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

8 lines (7 loc) 3.29 kB
{ "version": 3, "sources": ["../../../src/lib/hooks/useEvent.tsx"], "sourcesContent": ["import { useAtom } from '@tldraw/state-react'\nimport { assert } from '@tldraw/utils'\nimport { useCallback, useDebugValue, useLayoutEffect, useRef } from 'react'\n\n/**\n * Allows you to define event handlers that can read the latest props/state but has a stable\n * function identity.\n *\n * These event callbacks may not be called in React render functions! An error won't be thrown, but\n * in the real implementation it would be!\n *\n * Uses a modified version of the user-land implementation included in the [`useEvent()` RFC][1].\n * Our version until such a hook is available natively.\n *\n * The RFC was closed on 27 September 2022, the React team plans to come up with a new RFC to\n * provide similar functionality in the future. We will migrate to this functionality when\n * available.\n *\n * IMPORTANT CAVEAT: You should not call event callbacks in layout effects of React component\n * children! Internally this hook uses a layout effect and parent component layout effects run after\n * child component layout effects. Use this hook responsibly.\n *\n * [1]: https://github.com/reactjs/rfcs/pull/220\n *\n * @internal\n */\nexport function useEvent<Args extends Array<unknown>, Result>(\n\thandler: (...args: Args) => Result\n): (...args: Args) => Result {\n\tconst handlerRef = useRef<(...args: Args) => Result>()\n\n\t// In a real implementation, this would run before layout effects\n\tuseLayoutEffect(() => {\n\t\thandlerRef.current = handler\n\t})\n\n\tuseDebugValue(handler)\n\n\treturn useCallback((...args: Args) => {\n\t\t// In a real implementation, this would throw if called during render\n\t\tconst fn = handlerRef.current\n\t\tassert(fn, 'fn does not exist')\n\t\treturn fn(...args)\n\t}, [])\n}\n\n/**\n * like {@link useEvent}, but for use in reactive contexts - when the handler function changes, it\n * will invalidate any reactive contexts that call it.\n * @internal\n */\nexport function useReactiveEvent<Args extends Array<unknown>, Result>(\n\thandler: (...args: Args) => Result\n): (...args: Args) => Result {\n\tconst handlerAtom = useAtom<(...args: Args) => Result>('useReactiveEvent', () => handler)\n\n\t// In a real implementation, this would run before layout effects\n\tuseLayoutEffect(() => {\n\t\thandlerAtom.set(handler)\n\t})\n\n\tuseDebugValue(handler)\n\n\treturn useCallback(\n\t\t(...args: Args) => {\n\t\t\t// In a real implementation, this would throw if called during render\n\t\t\tconst fn = handlerAtom.get()\n\t\t\tassert(fn, 'fn does not exist')\n\t\t\treturn fn(...args)\n\t\t},\n\t\t[handlerAtom]\n\t)\n}\n"], "mappings": "AAAA,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,aAAa,eAAe,iBAAiB,cAAc;AAwB7D,SAAS,SACf,SAC4B;AAC5B,QAAM,aAAa,OAAkC;AAGrD,kBAAgB,MAAM;AACrB,eAAW,UAAU;AAAA,EACtB,CAAC;AAED,gBAAc,OAAO;AAErB,SAAO,YAAY,IAAI,SAAe;AAErC,UAAM,KAAK,WAAW;AACtB,WAAO,IAAI,mBAAmB;AAC9B,WAAO,GAAG,GAAG,IAAI;AAAA,EAClB,GAAG,CAAC,CAAC;AACN;AAOO,SAAS,iBACf,SAC4B;AAC5B,QAAM,cAAc,QAAmC,oBAAoB,MAAM,OAAO;AAGxF,kBAAgB,MAAM;AACrB,gBAAY,IAAI,OAAO;AAAA,EACxB,CAAC;AAED,gBAAc,OAAO;AAErB,SAAO;AAAA,IACN,IAAI,SAAe;AAElB,YAAM,KAAK,YAAY,IAAI;AAC3B,aAAO,IAAI,mBAAmB;AAC9B,aAAO,GAAG,GAAG,IAAI;AAAA,IAClB;AAAA,IACA,CAAC,WAAW;AAAA,EACb;AACD;", "names": [] }