Skip to main content

Hooks

Import React hooks from react (aliased to @kog/react); Kog-specific hooks from @kog/react or @kog/ui as noted. Semantics differ from React in six deliberate ways — read Thinking in Kog first.

React-compatible

HookNotes in Kog
useState(initial)Returns [value, setValue]. Writes are synchronous; UI flush batched. Functional updates supported.
useReducer(reducer, init)As React.
useEffect(fn, deps?)Runs after mount; re-runs when deps change; cleanup on unmount/re-run. [] = mount-only. Omitted deps = auto-tracked (lint warning).
useLayoutEffectSame, flushed synchronously before the frame.
useMemo(fn, deps)A true derived value (recomputes when its inputs change, cached otherwise) — and optional for pure derivations: a bare const computed from state/props in the body is kept live by the compiler automatically; useMemo is the same memo spelled explicitly, and the required form when the compiler refuses an initializer it can't prove side-effect-free.
useCallback(fn)Identity — functions are already stable. Kept for compatibility.
useRef(initial)Stable { current }, non-reactive. With ref={...} on a component, .current is the native widget handle (escape hatch).
createContext / useContextFine-grained: consumers update without re-running.
useImperativeHandle, forwardRefMinimal support.
useSyncExternalStoreShim over a store subscription.

Not present: useTransition, useDeferredValue (identity shim), Suspense-related hooks. There is no concurrency to schedule around — updates are already minimal.

Timing

HookSignature
useInterval(fn, ms | null)Auto-cleans; ms may be reactive; null pauses.
useTimeout(fn, ms | null)Same contract.
useAnimatedValue(initial, config?)A value driven by the native animation engine — zero JS per frame. Bind it to a widget prop (<View width={anim} />), then anim.animate(to, { duration, easing }). Values are in the prop's native units — px for size/position, and 0–255 for opacity (not the 0–1 used for static opacity).

Device & app

HookReturns
useDisplay(){ width, height, shape, safeRect, insetAt(y), contains(x,y), dpi, rotation } — display geometry in logical px, snapshot (it cannot change at runtime). On shaped glass (the round Waveshare 1.46B, notched panels, arbitrary outlines) safeRect is the largest rectangle fully on the glass and insetAt(y) is the usable width of a row (the chord, on a circle) for shape-hugging layouts. dpi and rotation are static placeholders today — don't build on them. Pair with <SafeAreaView> from @kog/ui for the common "keep my content on the glass" case.
useDevice(){ heapFree, battery, rssi } — v1 stub (zeros) until the device namespace lands.
useColorScheme()'light' | 'dark' — v1 snapshot (not reactive).
useStorage(key, default)useState-shaped; v1 is in-memory only (NVS persistence is a follow-up).
useFocusEffect(fn) / useIsFocused()Route focus lifecycle. In Kog focus and mount are the same event — a route that is not focused is not mounted — so useFocusEffect runs on mount and its cleanup is the blur handler, and useIsFocused() is always true. Kept for React Navigation-shaped source.

Routing

useNavigate, useLocation, useParams, useSearchParams, useMatch, useResolvedPath, useOutletContext, useNavigationType — all from @kog/router, documented in the Router reference.

Hardware

useButton, useDigitalRead, useDigitalWrite, useAnalogRead, usePWM — documented in Hardware. Read hooks return accessors in v1 (call them: mv(), pressed()); useDigitalWrite is [value, setValue] like useState. One caveat: derive from accessors where you read them, not in the body — const volts = mv() / 1000 at the top level freezes at its mount-time value, because the compiler cannot see that mv() is reactive (it looks like any other call). Call it inline ({(mv() / 1000).toFixed(2)}) or wrap the derivation in useMemo; the no-reactivity-loss lint flags the frozen form.