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
116 lines
2.8 KiB
Plaintext
116 lines
2.8 KiB
Plaintext
---
|
|
title: Quickstart
|
|
description: Install Store and connect your first Tap resource to React.
|
|
---
|
|
|
|
Store (`@assistant-ui/store`) connects Tap resources to React with scoped, type-safe state management.
|
|
|
|
## Installation
|
|
|
|
```sh
|
|
npm install @assistant-ui/store @assistant-ui/tap
|
|
```
|
|
|
|
## Define your scope types
|
|
|
|
Register your scopes by augmenting the `ScopeRegistry` interface. This gives you type safety across all Store hooks.
|
|
|
|
```ts title="lib/store/counter-scope.ts"
|
|
import "@assistant-ui/store";
|
|
|
|
declare module "@assistant-ui/store" {
|
|
interface ScopeRegistry {
|
|
counter: {
|
|
methods: {
|
|
getState: () => { count: number };
|
|
increment: () => void;
|
|
};
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
## Create a resource
|
|
|
|
Define a Tap resource that returns `ClientOutput<"counter">`. This connects the resource's methods to the scope type you just registered.
|
|
|
|
```ts title="lib/store/counter-store.ts"
|
|
import { resource } from "@assistant-ui/tap";
|
|
import { useState, useMemo } from "react";
|
|
import type { ClientOutput } from "@assistant-ui/store";
|
|
|
|
const useCounterResource = ({
|
|
initialCount = 0,
|
|
}: {
|
|
initialCount?: number;
|
|
}): ClientOutput<"counter"> => {
|
|
const [count, setCount] = useState(initialCount);
|
|
|
|
const state = useMemo(() => ({ count }), [count]);
|
|
|
|
return {
|
|
getState: () => state,
|
|
increment: () => setCount((c) => c + 1),
|
|
};
|
|
};
|
|
|
|
export const CounterResource = resource(useCounterResource);
|
|
```
|
|
|
|
## Use it in React
|
|
|
|
Use `useAui` to create a store, `AuiProvider` to provide it to the tree, and `useAuiState` to subscribe to state.
|
|
|
|
```tsx title="app/CounterApp.tsx"
|
|
"use client";
|
|
|
|
import { useAui, AuiProvider } from "@assistant-ui/store";
|
|
import { CounterResource } from "@/lib/store/counter-store";
|
|
import { CounterDisplay } from "./CounterDisplay";
|
|
|
|
export const CounterApp = () => {
|
|
const aui = useAui({
|
|
counter: CounterResource({ initialCount: 0 }),
|
|
});
|
|
|
|
return (
|
|
<AuiProvider value={aui}>
|
|
<CounterDisplay />
|
|
</AuiProvider>
|
|
);
|
|
};
|
|
```
|
|
|
|
```tsx title="app/CounterDisplay.tsx"
|
|
"use client";
|
|
|
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
|
|
export const CounterDisplay = () => {
|
|
const count = useAuiState((s) => s.counter.count);
|
|
const aui = useAui();
|
|
|
|
return (
|
|
<div>
|
|
<p>Count: {count}</p>
|
|
<button onClick={() => aui.counter().increment()}>+</button>
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
`useAuiState((s) => s.counter.count)` subscribes to just the `count` value, so the component only re-renders when it changes.
|
|
|
|
`aui.counter()` returns the methods object, so `aui.counter().increment()` calls the `increment` method you defined in the resource.
|
|
|
|
## Next steps
|
|
|
|
<Cards>
|
|
<Card title="Scopes" href="/tap/docs/store/scopes">
|
|
Nest scopes with Derived and AuiProvider.
|
|
</Card>
|
|
<Card title="Events" href="/tap/docs/store/events">
|
|
Emit and subscribe to typed events.
|
|
</Card>
|
|
</Cards>
|