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/write
A 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 here
Only 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.