e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
96 lines
3.0 KiB
Plaintext
96 lines
3.0 KiB
Plaintext
---
|
|
title: Resources
|
|
description: Define resources, pass props, and host them.
|
|
---
|
|
|
|
A **resource** is a self-contained unit of reactive state and logic: like a React
|
|
component, but without UI.
|
|
|
|
## Defining a resource
|
|
|
|
A resource body **is a hook**: a function that calls the React hooks you know,
|
|
imported from `"react"`. Write it as a `use`-prefixed hook, then pass it to
|
|
`resource()` to turn it into a Resource.
|
|
|
|
```ts
|
|
import { resource } from "@assistant-ui/tap";
|
|
import { useState } from "react";
|
|
|
|
const useCounter = (props: { initialValue?: number }) => {
|
|
const [count, setCount] = useState(props.initialValue ?? 0);
|
|
|
|
return { count, increment: () => setCount((c) => c + 1) };
|
|
};
|
|
|
|
const Counter = resource(useCounter);
|
|
```
|
|
|
|
`resource()` turns a hook into a Resource, and [`useResource`](#hosting-a-resource)
|
|
turns it back into a hook call. Keep the body in a `use`-prefixed binding: it gives
|
|
the resource a stable identity for keys and devtools, and lets React's
|
|
rules-of-hooks lint the body.
|
|
|
|
`resource()` returns a **factory function**. Calling the factory creates a
|
|
`ResourceElement`, a lightweight description of what to render, not a live
|
|
instance yet.
|
|
|
|
### Resource elements
|
|
|
|
A `ResourceElement` is a plain `{ hook, args }` object, the same idea as a React
|
|
JSX element, but written as a function call instead of JSX.
|
|
|
|
```ts
|
|
const element = Counter({ initialValue: 10 });
|
|
// { hook: useCounter, args: [{ initialValue: 10 }] }
|
|
```
|
|
|
|
Calling the factory (`Counter({ ... })`) reads like the plain function call it
|
|
is. Like a JSX element, the result is inert until you host it.
|
|
|
|
### Props
|
|
|
|
Resources accept props like components do. When a resource re-renders with new
|
|
props, hooks react to the change through their dependency arrays, exactly as in
|
|
React.
|
|
|
|
### Return value
|
|
|
|
Instead of JSX, a resource returns any JavaScript value: an object, array, or
|
|
primitive. That return value is the resource's public API, and it is what callers
|
|
read when they host it.
|
|
|
|
## Hosting a resource
|
|
|
|
`useResource` hosts a single element, re-entering the Resource as a hook call. It
|
|
works the same way in both worlds: inside a React component it ties the resource to
|
|
the component's lifecycle, and inside another resource it nests the resource as a
|
|
child.
|
|
|
|
```tsx
|
|
import { useResource } from "@assistant-ui/tap";
|
|
|
|
function CounterButton() {
|
|
const { count, increment } = useResource(Counter({ initialValue: 10 }));
|
|
return <button onClick={increment}>Count: {count}</button>;
|
|
}
|
|
```
|
|
|
|
Unlike React, a parent reads its child's return value directly, which makes
|
|
composition a tool for building up state and logic, not just trees.
|
|
|
|
```ts
|
|
import { resource, useResource } from "@assistant-ui/tap";
|
|
|
|
const useDashboard = () => {
|
|
const counter = useResource(Counter({ initialValue: 0 }));
|
|
return { total: counter.count };
|
|
};
|
|
|
|
const Dashboard = resource(useDashboard);
|
|
```
|
|
|
|
## Next
|
|
|
|
- [Composition](/tap/docs/tap/composition): render keyed lists with `useResources` and expose subscribable boundaries with `useTapRoot`.
|
|
- [Context](/tap/docs/tap/context): pass values through the resource tree without prop drilling.
|