0
# React Integration
1
2
React hooks and components for integrating Jotai atoms with React applications. These provide the primary interface for using atoms in React components.
3
4
## Capabilities
5
6
### useAtom Hook
7
8
Primary hook for reading and writing atom values in React components.
9
10
```typescript { .api }
11
/**
12
* Hook for reading and writing writable atoms
13
* @param atom - The writable atom to use
14
* @param options - Optional configuration
15
* @returns Tuple of [value, setter] similar to useState
16
*/
17
function useAtom<Value, Args extends unknown[], Result>(
18
atom: WritableAtom<Value, Args, Result>,
19
options?: Options
20
): [Awaited<Value>, SetAtom<Args, Result>];
21
22
/**
23
* Hook for reading and writing primitive atoms
24
* @param atom - The primitive atom to use
25
* @param options - Optional configuration
26
* @returns Tuple of [value, setter] with standard setState interface
27
*/
28
function useAtom<Value>(
29
atom: PrimitiveAtom<Value>,
30
options?: Options
31
): [Awaited<Value>, SetAtom<[SetStateAction<Value>], void>];
32
33
/**
34
* Hook for read-only atoms (returns never for setter)
35
* @param atom - The read-only atom to use
36
* @param options - Optional configuration
37
* @returns Tuple of [value, never]
38
*/
39
function useAtom<Value>(
40
atom: Atom<Value>,
41
options?: Options
42
): [Awaited<Value>, never];
43
```
44
45
**Usage Examples:**
46
47
```typescript
48
import { atom, useAtom } from "jotai";
49
50
const countAtom = atom(0);
51
const textAtom = atom("hello");
52
53
function MyComponent() {
54
const [count, setCount] = useAtom(countAtom);
55
const [text, setText] = useAtom(textAtom);
56
57
return (
58
<div>
59
<p>Count: {count}</p>
60
<button onClick={() => setCount(count + 1)}>+</button>
61
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
62
63
<input
64
value={text}
65
onChange={(e) => setText(e.target.value)}
66
/>
67
</div>
68
);
69
}
70
```
71
72
### useAtomValue Hook
73
74
Hook for reading atom values without the ability to write.
75
76
```typescript { .api }
77
/**
78
* Hook for reading atom values without write capability
79
* @param atom - The atom to read from
80
* @param options - Optional configuration
81
* @returns The current value of the atom
82
*/
83
function useAtomValue<Value>(
84
atom: Atom<Value>,
85
options?: Options
86
): Awaited<Value>;
87
```
88
89
**Usage Examples:**
90
91
```typescript
92
import { atom, useAtomValue } from "jotai";
93
94
const countAtom = atom(0);
95
const doubleCountAtom = atom((get) => get(countAtom) * 2);
96
97
function DisplayComponent() {
98
const count = useAtomValue(countAtom);
99
const doubleCount = useAtomValue(doubleCountAtom);
100
101
return (
102
<div>
103
<p>Count: {count}</p>
104
<p>Double: {doubleCount}</p>
105
</div>
106
);
107
}
108
```
109
110
### useSetAtom Hook
111
112
Hook for getting a setter function for writable atoms.
113
114
```typescript { .api }
115
/**
116
* Hook for getting a setter function for writable atoms
117
* @param atom - The writable atom to get setter for
118
* @param options - Optional configuration
119
* @returns Setter function for the atom
120
*/
121
function useSetAtom<Value, Args extends unknown[], Result>(
122
atom: WritableAtom<Value, Args, Result>,
123
options?: Options
124
): SetAtom<Args, Result>;
125
126
/**
127
* Hook for getting a setter function for primitive atoms
128
* @param atom - The primitive atom to get setter for
129
* @param options - Optional configuration
130
* @returns Standard setState-style setter function
131
*/
132
function useSetAtom<Value>(
133
atom: PrimitiveAtom<Value>,
134
options?: Options
135
): SetAtom<[SetStateAction<Value>], void>;
136
```
137
138
**Usage Examples:**
139
140
```typescript
141
import { atom, useSetAtom, useAtomValue } from "jotai";
142
143
const countAtom = atom(0);
144
const incrementAtom = atom(null, (get, set, amount: number) => {
145
set(countAtom, get(countAtom) + amount);
146
});
147
148
function Controls() {
149
const setCount = useSetAtom(countAtom);
150
const increment = useSetAtom(incrementAtom);
151
152
return (
153
<div>
154
<button onClick={() => setCount(0)}>Reset</button>
155
<button onClick={() => setCount((prev) => prev + 1)}>+1</button>
156
<button onClick={() => increment(5)}>+5</button>
157
</div>
158
);
159
}
160
161
function Display() {
162
const count = useAtomValue(countAtom);
163
return <p>Count: {count}</p>;
164
}
165
```
166
167
### Provider Component
168
169
React context provider for scoped atom stores.
170
171
```typescript { .api }
172
/**
173
* Provider component for scoped atom stores
174
* @param props - Component props
175
* @param props.children - React children
176
* @param props.store - Optional custom store, creates new one if not provided
177
* @returns ReactElement with store context
178
*/
179
function Provider(props: {
180
children?: ReactNode;
181
store?: Store;
182
}): ReactElement<
183
{ value: Store | undefined },
184
FunctionComponent<{ value: Store | undefined }>
185
>;
186
```
187
188
**Usage Examples:**
189
190
```typescript
191
import { Provider, createStore, atom, useAtom } from "jotai";
192
193
const countAtom = atom(0);
194
195
function App() {
196
return (
197
<Provider>
198
<Counter />
199
</Provider>
200
);
201
}
202
203
// With custom store
204
function AppWithCustomStore() {
205
const myStore = createStore();
206
207
return (
208
<Provider store={myStore}>
209
<Counter />
210
</Provider>
211
);
212
}
213
214
function Counter() {
215
const [count, setCount] = useAtom(countAtom);
216
return (
217
<div>
218
<p>{count}</p>
219
<button onClick={() => setCount((c) => c + 1)}>+</button>
220
</div>
221
);
222
}
223
```
224
225
### useStore Hook
226
227
Hook for accessing the current store context.
228
229
```typescript { .api }
230
/**
231
* Hook for accessing the current store context
232
* @param options - Optional configuration with custom store
233
* @returns The current store instance
234
*/
235
function useStore(options?: Options): Store;
236
237
interface Options {
238
store?: Store;
239
}
240
```
241
242
**Usage Examples:**
243
244
```typescript
245
import { useStore, atom } from "jotai";
246
247
const countAtom = atom(0);
248
249
function MyComponent() {
250
const store = useStore();
251
252
const handleDirectAccess = () => {
253
// Direct store access (not recommended for normal use)
254
const currentCount = store.get(countAtom);
255
store.set(countAtom, currentCount + 1);
256
};
257
258
return (
259
<button onClick={handleDirectAccess}>
260
Direct Store Access
261
</button>
262
);
263
}
264
265
// Using custom store
266
function MyComponentWithCustomStore() {
267
const customStore = createStore();
268
const store = useStore({ store: customStore });
269
270
// Store operations...
271
}
272
```
273
274
## Types and Interfaces
275
276
### Hook Options
277
278
Configuration options for hooks.
279
280
```typescript { .api }
281
interface Options {
282
/** Optional custom store to use instead of context store */
283
store?: Store;
284
}
285
```
286
287
### SetAtom Type
288
289
Type for atom setter functions returned by hooks.
290
291
```typescript { .api }
292
type SetAtom<Args extends unknown[], Result> = <A extends Args>(
293
...args: A
294
) => Result;
295
```
296
297
### React Types
298
299
React-specific types used by components and hooks.
300
301
```typescript { .api }
302
type ReactNode = React.ReactNode;
303
type ReactElement<P = any, T = any> = React.ReactElement<P, T>;
304
type FunctionComponent<P = {}> = React.FunctionComponent<P>;
305
```
306
307
## Advanced Usage Patterns
308
309
### Conditional Rendering with Suspense
310
311
```typescript
312
import { Suspense } from "react";
313
import { atom, useAtomValue } from "jotai";
314
315
const asyncDataAtom = atom(async () => {
316
const response = await fetch("/api/data");
317
return response.json();
318
});
319
320
function AsyncComponent() {
321
const data = useAtomValue(asyncDataAtom);
322
return <div>{JSON.stringify(data)}</div>;
323
}
324
325
function App() {
326
return (
327
<Suspense fallback={<div>Loading...</div>}>
328
<AsyncComponent />
329
</Suspense>
330
);
331
}
332
```
333
334
### Error Boundaries with Async Atoms
335
336
```typescript
337
import { ErrorBoundary } from "react-error-boundary";
338
import { atom, useAtomValue } from "jotai";
339
340
const errorAtom = atom(async () => {
341
throw new Error("Something went wrong");
342
});
343
344
function ErrorComponent() {
345
const data = useAtomValue(errorAtom);
346
return <div>{data}</div>;
347
}
348
349
function App() {
350
return (
351
<ErrorBoundary fallback={<div>Error occurred!</div>}>
352
<Suspense fallback={<div>Loading...</div>}>
353
<ErrorComponent />
354
</Suspense>
355
</ErrorBoundary>
356
);
357
}
358
```
359
360
### Multiple Stores
361
362
```typescript
363
import { Provider, createStore, atom, useAtom } from "jotai";
364
365
const userStore = createStore();
366
const appStore = createStore();
367
368
const userAtom = atom({ name: "Alice" });
369
const themeAtom = atom("light");
370
371
function App() {
372
return (
373
<Provider store={appStore}>
374
<ThemeProvider />
375
<Provider store={userStore}>
376
<UserProfile />
377
</Provider>
378
</Provider>
379
);
380
}
381
382
function ThemeProvider() {
383
const [theme, setTheme] = useAtom(themeAtom);
384
return (
385
<div className={`theme-${theme}`}>
386
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
387
Toggle Theme
388
</button>
389
</div>
390
);
391
}
392
393
function UserProfile() {
394
const [user, setUser] = useAtom(userAtom);
395
return (
396
<div>
397
<p>User: {user.name}</p>
398
<button onClick={() => setUser({ name: "Bob" })}>
399
Change User
400
</button>
401
</div>
402
);
403
}
404
```