Skip to content

Commit 7236a8d

Browse files
committed
Add readmes
1 parent 2d2dd77 commit 7236a8d

File tree

2 files changed

+323
-0
lines changed

2 files changed

+323
-0
lines changed

packages/optimistic/README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# @TanStack/optimistic
2+
3+
A core library for creating fast optimistic updates with flexible backend support.
4+
5+
## Installation
6+
7+
```bash
8+
pnpm add @TanStack/optimistic
9+
```
10+
11+
## Overview
12+
13+
`@TanStack/optimistic` provides a robust solution for managing data synchronization between your frontend application and backend services. It offers:
14+
15+
- **Optimistic Updates**: Apply changes instantly in the UI while syncing in the background
16+
- **Flexible Backend Support**: Works with any backend or sync engine
17+
- **Immutable Snapshots**: Create immutable snapshots of updates that can be persisted and rolled back
18+
19+
## Core Concepts
20+
21+
### Collections
22+
23+
Collections are the central concept in `@TanStack/optimistic`. A collection represents a set of data that can be synchronized, queried, and modified. Each collection:
24+
25+
- Has a unique identifier
26+
- Contains data items
27+
- Provides CRUD operations (insert, update, delete)
28+
- Manages its own sync and persistence logic
29+
30+
### Transactions
31+
32+
All mutations in `@TanStack/optimistic` are handled through transactions. Transactions:
33+
34+
- Group related changes together
35+
- Track the state of mutations (pending, persisting, completed, failed)
36+
- Support rollback in case of errors
37+
- Provide optimistic updates to the UI
38+
39+
### Proxies
40+
41+
The library uses proxies to create immutable snapshots and track changes:
42+
43+
- Deep change tracking at any level of object nesting
44+
- Special handling for various types (Date, RegExp, Map, Set)
45+
- Circular reference handling with WeakMap cache
46+
47+
## Framework Adapters
48+
49+
This is a core package that provides the fundamental optimistic update functionality. For most applications, you'll want to use this package with a framework-specific adapter:
50+
51+
- `@TanStack/react-optimistic` - React adapter with hooks for easy integration
52+
- Other framework adapters (coming soon)
53+
54+
The framework adapters provide idiomatic ways to use the core optimistic update functionality within your chosen framework.
55+
56+
## API Reference
57+
58+
### Data Operations
59+
60+
#### Insert
61+
62+
```typescript
63+
// Insert a single item
64+
insert({ text: "Buy groceries", completed: false })
65+
66+
// Insert multiple items
67+
insert([
68+
{ text: "Buy groceries", completed: false },
69+
{ text: "Walk dog", completed: false },
70+
])
71+
72+
// Insert with custom key
73+
insert({ text: "Buy groceries" }, { key: "grocery-task" })
74+
```
75+
76+
#### Update
77+
78+
We use a proxy to capture updates as immutable draft optimistic updates.
79+
80+
```typescript
81+
// Update a single item
82+
update(todo, (draft) => {
83+
draft.completed = true
84+
})
85+
86+
// Update multiple items
87+
update([todo1, todo2], (drafts) => {
88+
drafts.forEach((draft) => {
89+
draft.completed = true
90+
})
91+
})
92+
93+
// Update with metadata
94+
update(todo, { metadata: { reason: "user update" } }, (draft) => {
95+
draft.text = "Updated text"
96+
})
97+
```
98+
99+
#### Delete
100+
101+
```typescript
102+
// Delete a single item
103+
delete todo
104+
105+
// Delete multiple items
106+
delete [todo1, todo2]
107+
108+
// Delete with metadata
109+
delete (todo, { metadata: { reason: "completed" } })
110+
```
111+
112+
### Schema Validation
113+
114+
Collections can optionally include a [standard schema](https://github.com/standard-schema/standard-schema) for data validation:
115+
116+
```typescript
117+
const todoCollection = createCollection({
118+
id: "todos",
119+
sync: {
120+
/* sync config */
121+
},
122+
mutationFn: {
123+
/* mutation functions */
124+
},
125+
schema: todoSchema, // Standard schema interface
126+
})
127+
```
128+
129+
## Transaction Management
130+
131+
The library includes a robust transaction management system:
132+
133+
- `TransactionManager`: Handles transaction lifecycle, persistence, and retry logic
134+
- `TransactionStore`: Provides persistent storage for transactions using IndexedDB
135+
136+
Transactions progress through several states:
137+
138+
1. `pending`: Initial state when a transaction is created
139+
2. `persisting`: Transaction is being persisted to the backend
140+
3. `completed`: Transaction has been successfully persisted
141+
4. `failed`: An error was thrown while persisting or syncing back the Transaction
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# @TanStack/react-optimistic
2+
3+
React hooks and utilities for creating fast optimistic updates with flexible backend support that pairs seamlessly with sync engines (like [ElectricSQL](https://electric-sql.com/)).
4+
5+
## Installation
6+
7+
```bash
8+
pnpm add @TanStack/react-optimistic
9+
```
10+
11+
## Overview
12+
13+
`@TanStack/react-optimistic` provides React-specific hooks and utilities for managing data synchronization between your frontend application and backend services. It offers:
14+
15+
- **Optimistic Updates**: Apply changes instantly in the UI while syncing in the background
16+
- **Flexible Backend Support**: Works with any backend or sync engine
17+
- **Immutable Snapshots**: Create immutable snapshots of updates that can be persisted and rolled back
18+
- **React Integration**: Seamless integration with React components and state management
19+
20+
## React Hooks
21+
22+
### `useCollection`
23+
24+
The primary hook for interacting with collections in React components.
25+
26+
```typescript
27+
const { data, insert, update, delete: deleteFn } = useCollection({
28+
id: 'todos',
29+
sync: { /* sync configuration */ },
30+
mutationFn: { /* mutation functions */ },
31+
schema: /* optional schema */
32+
});
33+
```
34+
35+
Returns:
36+
37+
- `data`: An array of all items in the collection
38+
- `state`: A Map containing all items in the collection with their internal keys
39+
- `insert`: Function to add new items to the collection
40+
- `update`: Function to modify existing items
41+
- `delete`: Function to remove items from the collection
42+
43+
### `preloadCollection`
44+
45+
Preloads data for a collection before rendering components.
46+
47+
```typescript
48+
await preloadCollection({
49+
id: 'todos',
50+
sync: { /* sync configuration */ },
51+
mutationFn: { /* mutation functions */ },
52+
schema: /* optional schema */
53+
});
54+
```
55+
56+
Features:
57+
58+
1. Returns a promise that resolves when the first sync commit is complete
59+
2. Shares the same collection instance with `useCollection`
60+
3. Handles already-loaded collections by returning immediately
61+
4. Avoids duplicate initialization when called multiple times with the same ID
62+
63+
## Data Operations
64+
65+
### Insert
66+
67+
```typescript
68+
// Insert a single item
69+
insert({ text: "Buy groceries", completed: false })
70+
71+
// Insert multiple items
72+
insert([
73+
{ text: "Buy groceries", completed: false },
74+
{ text: "Walk dog", completed: false },
75+
])
76+
77+
// Insert with custom key
78+
insert({ text: "Buy groceries" }, { key: "grocery-task" })
79+
```
80+
81+
### Update
82+
83+
We use a proxy to capture updates as immutable draft optimistic updates.
84+
85+
```typescript
86+
// Update a single item
87+
update(todo, (draft) => {
88+
draft.completed = true
89+
})
90+
91+
// Update multiple items
92+
update([todo1, todo2], (drafts) => {
93+
drafts.forEach((draft) => {
94+
draft.completed = true
95+
})
96+
})
97+
98+
// Update with metadata
99+
update(todo, { metadata: { reason: "user update" } }, (draft) => {
100+
draft.text = "Updated text"
101+
})
102+
```
103+
104+
### Delete
105+
106+
```typescript
107+
// Delete a single item
108+
delete todo
109+
110+
// Delete multiple items
111+
delete [todo1, todo2]
112+
113+
// Delete with metadata
114+
delete (todo, { metadata: { reason: "completed" } })
115+
```
116+
117+
## Implementing Backend Integration with ElectricSQL
118+
119+
The `mutationFn` property is where you define how your application interacts with your backend. Here's a comprehensive example of integrating with ElectricSQL:
120+
121+
```typescript
122+
import { useCollection } from "@TanStack/react-optimistic"
123+
import { createElectricSync } from '@TanStack/optimistic/electric';
124+
125+
// Create a collection configuration for todos
126+
const todosConfig = {
127+
id: 'todos',
128+
// Create an ElectricSQL sync configuration
129+
sync: createElectricSync(
130+
{
131+
// ShapeStream options
132+
url: `http://localhost:3000/v1/shape`,
133+
params: {
134+
table: 'todos',
135+
},
136+
},
137+
{
138+
// Electric client instance
139+
client: electric,
140+
}
141+
),
142+
// Define mutation functions for backend persistence
143+
mutationFn: {
144+
insert: async (items) => {
145+
// Insert items into Electric database
146+
const db = electric.db;
147+
await db.todos.createMany({
148+
data: items,
149+
});
150+
},
151+
update: async (items) => {
152+
// Update items in Electric database
153+
const db = electric.db;
154+
for (const item of items) {
155+
await db.todos.update({
156+
where: { id: item.id },
157+
data: item,
158+
});
159+
}
160+
},
161+
delete: async (items) => {
162+
// Delete items from Electric database
163+
const db = electric.db;
164+
await db.todos.deleteMany({
165+
where: {
166+
id: {
167+
in: items.map((item) => item.id),
168+
},
169+
},
170+
});
171+
},
172+
},
173+
};
174+
175+
// Use the collection in a component
176+
function TodoList() {
177+
const { data, insert, update, delete: deleteFn } = useCollection(todosConfig);
178+
179+
// Now you can use these functions to interact with your data
180+
// with automatic optimistic updates and backend persistence
181+
}
182+
```

0 commit comments

Comments
 (0)