All exports from @assistant-ui/tap.
resource
Creates a resource factory function.
import { resource } from "@assistant-ui/tap";
const Counter = resource((props: { initialValue: number }) => {
const [count, setCount] = tapState(props.initialValue);
return { count, increment: () => setCount((c) => c + 1) };
});Returns a factory function — calling it produces a ResourceElement.
withKey
Attaches a key to a ResourceElement for identity preservation in lists.
import { withKey } from "@assistant-ui/tap";
withKey("my-key", Counter({ initialValue: 0 }))Hooks
All hooks follow the rules of hooks.
tapState
const [value, setValue] = tapState(initialValue);
const [value, setValue] = tapState(() => expensiveDefault());Local state. setValue accepts a value or an updater function (prev) => next.
tapReducer
const [state, dispatch] = tapReducer(reducer, initialState);
const [state, dispatch] = tapReducer(reducer, initialArg, init);State management with a reducer function. dispatch has a stable identity. Bails out (no re-render) when the reducer returns the same state via Object.is.
tapReducerWithDerivedState
This API is experimental, intended for advanced use cases, and may change.
const [state, dispatch] = tapReducerWithDerivedState(reducer, getDerivedState, initialState);
const [state, dispatch] = tapReducerWithDerivedState(reducer, getDerivedState, initialArg, init);Like tapReducer, but accepts a getDerivedState function as the second argument. During each render pass, getDerivedState(state) is called once after processing any queued actions. If it returns a new value (by Object.is), the derived value becomes the current state and triggers a re-render. The return type is inferred from getDerivedState, allowing you to narrow or extend the state type.
tapEffect
tapEffect(() => {
// side effect
return () => { /* cleanup */ };
}, [deps]);Runs after commit. Without a dependency array, runs after every render.
tapMemo
const value = tapMemo(() => compute(a, b), [a, b]);Memoizes a value. Recomputes when dependencies change.
tapCallback
const fn = tapCallback(() => { /* ... */ }, [deps]);Memoizes a function. Shorthand for tapMemo(() => fn, deps).
tapRef
const ref = tapRef(initialValue);
ref.current; // read/writeA mutable ref that persists across renders.
tapConst
const value = tapConst(() => new EventEmitter(), []);Computed once on mount, never recomputed. The second argument must always be [].
tapEffectEvent
const handler = tapEffectEvent((msg: string) => {
// always has access to latest closure
});Returns a stable function reference that always calls the latest version of the callback. Useful for event handlers passed to effects.
Composition hooks
tapResource
const value = tapResource(Counter({ initialValue: 0 }));
const value = tapResource(Counter({ initialValue }), [initialValue]);Renders a single child resource. Returns the child's return value.
The optional dependency array controls when new props are applied.
The dependency array API is experimental and may change.
tapResources
This API is experimental and may change.
const values = tapResources(
() => items.map((item) => withKey(item.id, TodoItem({ text: item.text }))),
[items],
);Renders a dynamic list of child resources. Every element must have a key via withKey.
tapResourceRoot
const handle = tapResourceRoot(Counter({ initialValue: 0 }));
handle.getValue(); // current value
handle.subscribe(() => { /* on change */ });Renders a child as a subscribable store. The parent doesn't re-render when the child updates.
Imperative API
createResourceRoot
Creates a resource instance outside of React.
import { createResourceRoot } from "@assistant-ui/tap";
const root = createResourceRoot();
const handle = root.render(Counter({ initialValue: 0 }));Root methods:
| Method | Description |
|---|---|
root.render(element) | Render (or re-render) with a resource element. Returns a subscribable handle. |
root.unmount() | Unmount and clean up |
Subscribable handle methods (returned by root.render()):
| Method | Description |
|---|---|
handle.getValue() | Read the current return value |
handle.subscribe(callback) | Subscribe to changes |
flushResourcesSync
Synchronously flushes pending tap scheduler updates.
import { flushResourcesSync } from "@assistant-ui/tap";
flushResourcesSync(() => {
handle.getValue().increment();
});
// state is already updated hereOnly applies to tap-scheduled trees (createResourceRoot / tapResourceRoot). For useResource trees, use flushSync from react-dom.
Context
The context API is experimental and may change significantly.
createResourceContext
import { createResourceContext } from "@assistant-ui/tap";
const ThemeContext = createResourceContext("light");Creates a context with a default value.
tap
import { tap } from "@assistant-ui/tap";
const theme = tap(ThemeContext);Reads the current value of a context inside a resource.
withContextProvider
import { withContextProvider } from "@assistant-ui/tap";
const child = withContextProvider(ThemeContext, "dark", () => {
return tapResource(Button());
});Provides a context value to all resources rendered within the callback.
React
useResource
import { useResource } from "@assistant-ui/tap/react";
const { count, increment } = useResource(Counter({ initialValue: 0 }));Binds a resource to a React component's lifecycle. The component re-renders when the resource's state changes.
Types
Resource
type Resource<R, P> = (props: P) => ResourceElement<R, P>;The factory function returned by resource().
ResourceElement
type ResourceElement<R, P> = { type: Resource<R, P>; props: P; key?: string | number };A lightweight { type, props } description of a resource to render.
ContravariantResource
type ContravariantResource<R, P> = (props: P) => ResourceElement<R>;A contravariant version of Resource for type-level flexibility when accepting resources as parameters. The difference from Resource is that the returned ResourceElement omits the P type parameter, allowing broader assignability.