UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

8 lines (7 loc) 2.52 kB
{ "version": 3, "sources": ["../../../src/lib/hooks/useRefState.ts"], "sourcesContent": ["import { Dispatch, SetStateAction, useCallback, useRef, useState } from 'react'\n\n/**\n * A `useState` that uses a `ref` to keep the state in sync with the last value assigned to it.\n *\n * This is useful when creating side-effect state that behave correctly in react strict mode. The\n * obvious way to do this is to use `useState` within a `useEffect` like this:\n *\n * ```ts\n * const [state, setState] = useState(null)\n * useEffect(() => {\n * const thing = createSideEffectThing()\n * setState(thing)\n * return () => thing.destroy()\n * }, [deps])\n * ```\n *\n * The problem with this is that when initially mounting in strict mode, react will:\n * - Call the initial effect and set state with an instance\n * - Call the cleanup function and destroy the instance\n * - Call the effect again and set state with a new instance\n * - Restore the state to the first instance\n *\n * Now, our effect and our state are out of sync: the effect is using the new instance, but the\n * state contains the old instance which has been destroyed.\n *\n * Using a `ref` is a solution, as it'll always keep the value last assigned to it, so it stays in\n * sync with the effect. That's no good for rendering though, as react won't trigger a re-render\n * when the contents of the ref changes.\n *\n * This hook solves this problem by using a `ref` to keep the value in sync with the effect, and\n * a `useState` to trigger a re-render when the value changes.\n *\n * @internal\n */\nexport function useRefState<T>(initialValue: T): [T, Dispatch<SetStateAction<T>>] {\n\tconst ref = useRef(initialValue)\n\tconst [state, setState] = useState(initialValue)\n\n\tif (state !== ref.current) {\n\t\tsetState(ref.current)\n\t}\n\n\tconst update: Dispatch<SetStateAction<T>> = useCallback((value) => {\n\t\tif (typeof value === 'function') {\n\t\t\tref.current = (value as any)(ref.current)\n\t\t} else {\n\t\t\tref.current = value\n\t\t}\n\n\t\tsetState(ref.current)\n\t}, [])\n\n\treturn [state, update]\n}\n"], "mappings": "AAAA,SAAmC,aAAa,QAAQ,gBAAgB;AAmCjE,SAAS,YAAe,cAAmD;AACjF,QAAM,MAAM,OAAO,YAAY;AAC/B,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,YAAY;AAE/C,MAAI,UAAU,IAAI,SAAS;AAC1B,aAAS,IAAI,OAAO;AAAA,EACrB;AAEA,QAAM,SAAsC,YAAY,CAAC,UAAU;AAClE,QAAI,OAAO,UAAU,YAAY;AAChC,UAAI,UAAW,MAAc,IAAI,OAAO;AAAA,IACzC,OAAO;AACN,UAAI,UAAU;AAAA,IACf;AAEA,aAAS,IAAI,OAAO;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,SAAO,CAAC,OAAO,MAAM;AACtB;", "names": [] }