or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdmiddleware.mdreact-integration.mdstore-creation.mdutilities.md

react-integration.mddocs/

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

```