UNPKG

@tldraw/state-react

Version:

tldraw infinite canvas SDK (react bindings for state).

8 lines (7 loc) 4.39 kB
{ "version": 3, "sources": ["../../src/lib/useValue.ts"], "sourcesContent": ["/* eslint-disable prefer-rest-params */\nimport { Signal, computed, react } from '@tldraw/state'\nimport { useMemo, useSyncExternalStore } from 'react'\n\n/**\n * Extracts the current value from a signal and subscribes the component to changes.\n *\n * This is the most straightforward way to read signal values in React components.\n * When the signal changes, the component will automatically re-render with the new value.\n *\n * Note: You do not need to use this hook if you are wrapping the component with {@link track},\n * as tracked components automatically subscribe to any signals accessed with `.get()`.\n *\n * @param value - The signal to read the value from\n * @returns The current value of the signal\n *\n * @example\n * ```ts\n * import { atom } from '@tldraw/state'\n * import { useValue } from '@tldraw/state-react'\n *\n * const count = atom('count', 0)\n *\n * function Counter() {\n * const currentCount = useValue(count)\n * return (\n * <button onClick={() => count.set(currentCount + 1)}>\n * Count: {currentCount}\n * </button>\n * )\n * }\n * ```\n *\n * @public\n */\nexport function useValue<Value>(value: Signal<Value>): Value\n\n/**\n * Creates a computed value with automatic dependency tracking and subscribes to changes.\n *\n * This overload allows you to compute a value from one or more signals with automatic\n * memoization. The computed function will only re-execute when its dependencies change,\n * and the component will only re-render when the computed result changes.\n *\n * @param name - A descriptive name for debugging purposes\n * @param fn - Function that computes the value, should call `.get()` on any signals it depends on\n * @param deps - Array of signals that the computed function depends on\n * @returns The computed value\n *\n * @example\n * ```ts\n * import { atom } from '@tldraw/state'\n * import { useValue } from '@tldraw/state-react'\n *\n * const firstName = atom('firstName', 'John')\n * const lastName = atom('lastName', 'Doe')\n *\n * function UserGreeting() {\n * const fullName = useValue('fullName', () => {\n * return `${firstName.get()} ${lastName.get()}`\n * }, [firstName, lastName])\n *\n * return <div>Hello {fullName}!</div>\n * }\n * ```\n *\n * @public\n */\nexport function useValue<Value>(name: string, fn: () => Value, deps: unknown[]): Value\n\n/**\n * Implementation function for useValue hook overloads.\n *\n * Handles both single signal subscription and computed value creation with dependency tracking.\n * Uses React's useSyncExternalStore for efficient subscription management and automatic cleanup.\n *\n * @internal\n */\nexport function useValue() {\n\tconst args = arguments\n\t// deps will be either the computed or the deps array\n\tconst deps = args.length === 3 ? args[2] : [args[0]]\n\tconst name = args.length === 3 ? args[0] : `useValue(${args[0].name})`\n\n\tconst { $val, subscribe, getSnapshot } = useMemo(() => {\n\t\tconst $val =\n\t\t\targs.length === 1 ? (args[0] as Signal<any>) : (computed(name, args[1]) as Signal<any>)\n\n\t\treturn {\n\t\t\t$val,\n\t\t\tsubscribe: (notify: () => void) => {\n\t\t\t\treturn react(`useValue(${name})`, () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t$val.get()\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Will be rethrown during render if the component doesn't unmount first.\n\t\t\t\t\t}\n\t\t\t\t\tnotify()\n\t\t\t\t})\n\t\t\t},\n\t\t\tgetSnapshot: () => $val.lastChangedEpoch,\n\t\t}\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, deps)\n\n\tuseSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\treturn $val.__unsafe__getWithoutCapture()\n}\n"], "mappings": "AACA,SAAiB,UAAU,aAAa;AACxC,SAAS,SAAS,4BAA4B;AA4EvC,SAAS,WAAW;AAC1B,QAAM,OAAO;AAEb,QAAM,OAAO,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnD,QAAM,OAAO,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE,IAAI;AAEnE,QAAM,EAAE,MAAM,WAAW,YAAY,IAAI,QAAQ,MAAM;AACtD,UAAMA,QACL,KAAK,WAAW,IAAK,KAAK,CAAC,IAAqB,SAAS,MAAM,KAAK,CAAC,CAAC;AAEvE,WAAO;AAAA,MACN,MAAAA;AAAA,MACA,WAAW,CAAC,WAAuB;AAClC,eAAO,MAAM,YAAY,IAAI,KAAK,MAAM;AACvC,cAAI;AACH,YAAAA,MAAK,IAAI;AAAA,UACV,QAAQ;AAAA,UAER;AACA,iBAAO;AAAA,QACR,CAAC;AAAA,MACF;AAAA,MACA,aAAa,MAAMA,MAAK;AAAA,IACzB;AAAA,EAED,GAAG,IAAI;AAEP,uBAAqB,WAAW,aAAa,WAAW;AACxD,SAAO,KAAK,4BAA4B;AACzC;", "names": ["$val"] }