0
# React Integration
1
2
React hooks and components for consuming Zustand stores with automatic re-rendering and selector support.
3
4
## Capabilities
5
6
### useStore Hook
7
8
Hook for consuming store state in React components with automatic re-rendering when selected state changes.
9
10
```typescript { .api }
11
/**
12
* Subscribe to entire store state
13
* @param api - Store API to subscribe to
14
* @returns Complete store state
15
*/
16
function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
17
18
/**
19
* Subscribe to selected portion of store state
20
* @param api - Store API to subscribe to
21
* @param selector - Function to select specific state slice
22
* @returns Selected state slice
23
*/
24
function useStore<S extends ReadonlyStoreApi<unknown>, U>(
25
api: S,
26
selector: (state: ExtractState<S>) => U
27
): U;
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { create } from "zustand";
34
35
const useStore = create((set) => ({
36
count: 0,
37
name: "John",
38
increment: () => set((state) => ({ count: state.count + 1 })),
39
}));
40
41
// Subscribe to entire state
42
function FullStateComponent() {
43
const state = useStore();
44
return <div>Count: {state.count}, Name: {state.name}</div>;
45
}
46
47
// Subscribe to specific state slice
48
function CountComponent() {
49
const count = useStore((state) => state.count);
50
return <div>Count: {count}</div>;
51
}
52
53
// Complex selector
54
function DerivedStateComponent() {
55
const isEven = useStore((state) => state.count % 2 === 0);
56
return <div>Count is {isEven ? 'even' : 'odd'}</div>;
57
}
58
```
59
60
### UseBoundStore Type
61
62
Combined hook and store API interface returned by the `create` function.
63
64
```typescript { .api }
65
/**
66
* Hook interface with store API methods
67
* Can be called as a hook with optional selector
68
*/
69
type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
70
/** Subscribe to entire store state */
71
(): ExtractState<S>;
72
/** Subscribe to selected state slice */
73
<U>(selector: (state: ExtractState<S>) => U): U;
74
} & S;
75
```
76
77
**Usage Examples:**
78
79
```typescript
80
const useCounterStore = create((set) => ({
81
count: 0,
82
increment: () => set((state) => ({ count: state.count + 1 })),
83
}));
84
85
// Use as hook - entire state
86
function Component1() {
87
const { count, increment } = useCounterStore();
88
return <button onClick={increment}>Count: {count}</button>;
89
}
90
91
// Use as hook - with selector
92
function Component2() {
93
const count = useCounterStore((state) => state.count);
94
return <div>Count: {count}</div>;
95
}
96
97
// Access store API methods directly
98
function Component3() {
99
const handleClick = () => {
100
useCounterStore.getState().increment();
101
};
102
103
return <button onClick={handleClick}>Increment</button>;
104
}
105
106
// Subscribe imperatively
107
useEffect(() => {
108
const unsubscribe = useCounterStore.subscribe((state, prevState) => {
109
console.log('Count changed:', prevState.count, '->', state.count);
110
});
111
112
return unsubscribe;
113
}, []);
114
```
115
116
### Traditional API with Equality Functions
117
118
Alternative API that provides custom equality function support for preventing unnecessary re-renders.
119
120
```typescript { .api }
121
/**
122
* Hook with custom equality function support
123
* @param api - Store API to subscribe to
124
* @returns Complete store state
125
*/
126
function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(
127
api: S
128
): ExtractState<S>;
129
130
/**
131
* Hook with selector and custom equality function
132
* @param api - Store API to subscribe to
133
* @param selector - Function to select specific state slice
134
* @param equalityFn - Custom equality function for comparing values
135
* @returns Selected state slice
136
*/
137
function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(
138
api: S,
139
selector: (state: ExtractState<S>) => U,
140
equalityFn?: (a: U, b: U) => boolean
141
): U;
142
143
/**
144
* Create store with default equality function
145
* @param initializer - Function that creates the initial state and actions
146
* @param defaultEqualityFn - Default equality function for all selectors
147
* @returns UseBoundStoreWithEqualityFn instance
148
*/
149
function createWithEqualityFn<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
150
initializer: StateCreator<T, [], Mos>,
151
defaultEqualityFn?: <U>(a: U, b: U) => boolean
152
): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
153
```
154
155
**Usage Examples:**
156
157
```typescript
158
import { createWithEqualityFn, useStoreWithEqualityFn } from "zustand/traditional";
159
160
// Store with default equality function
161
const useStore = createWithEqualityFn(
162
(set) => ({
163
users: [],
164
addUser: (user) => set((state) => ({ users: [...state.users, user] })),
165
}),
166
(a, b) => JSON.stringify(a) === JSON.stringify(b) // deep equality
167
);
168
169
// Use with custom equality function
170
function UserList() {
171
const users = useStoreWithEqualityFn(
172
useStore,
173
(state) => state.users,
174
(a, b) => a.length === b.length && a.every((user, i) => user.id === b[i].id)
175
);
176
177
return (
178
<ul>
179
{users.map(user => <li key={user.id}>{user.name}</li>)}
180
</ul>
181
);
182
}
183
```
184
185
### ReadonlyStoreApi Type
186
187
Type for store APIs that only expose read operations, used for type safety in hooks.
188
189
```typescript { .api }
190
/**
191
* Read-only interface for store API
192
* Excludes setState to prevent mutations from components
193
*/
194
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
195
```
196
197
### Performance Optimization Patterns
198
199
Best practices for optimizing React component re-renders with Zustand.
200
201
**Selector Optimization:**
202
203
```typescript
204
// ❌ Bad - creates new object every render, causes unnecessary re-renders
205
const { user, posts } = useStore((state) => ({
206
user: state.user,
207
posts: state.posts
208
}));
209
210
// ✅ Good - select minimal state
211
const user = useStore((state) => state.user);
212
const posts = useStore((state) => state.posts);
213
214
// ✅ Good - use shallow comparison for objects
215
import { useShallow } from "zustand/react/shallow";
216
const { user, posts } = useStore(useShallow((state) => ({
217
user: state.user,
218
posts: state.posts
219
})));
220
```
221
222
**Action Separation:**
223
224
```typescript
225
// ✅ Good - separate actions to prevent re-renders when actions change
226
const count = useStore((state) => state.count);
227
const increment = useStore((state) => state.increment);
228
229
// Or access actions directly from store
230
const handleIncrement = () => useStore.getState().increment();
231
```