or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

utilities.mddocs/

0

# Utilities

1

2

Helper functions for shallow comparison, state optimization, and performance improvements in Zustand applications.

3

4

## Capabilities

5

6

### Shallow Comparison

7

8

Deep equality comparison function for optimizing React re-renders and state subscriptions.

9

10

```typescript { .api }

11

/**

12

* Performs shallow comparison between two values

13

* Compares primitive values and top-level properties of objects/arrays

14

* @param valueA - First value to compare

15

* @param valueB - Second value to compare

16

* @returns true if values are shallowly equal, false otherwise

17

*/

18

function shallow<T>(valueA: T, valueB: T): boolean;

19

```

20

21

**Supported Data Types:**

22

- Primitives: strings, numbers, booleans, BigInt, symbols

23

- Objects: plain objects (top-level properties only)

24

- Arrays: element-by-element comparison

25

- Maps: key-value pair comparison

26

- Sets: element comparison (order independent)

27

- Iterables: ordered element comparison

28

- Functions: reference equality

29

30

**Usage Examples:**

31

32

```typescript

33

import { shallow } from "zustand/shallow";

34

35

// Primitive comparisons

36

shallow(1, 1); // true

37

shallow("hello", "hello"); // true

38

shallow(true, false); // false

39

40

// Object comparisons (shallow only)

41

shallow({ a: 1, b: 2 }, { a: 1, b: 2 }); // true

42

shallow({ a: 1, b: 2 }, { b: 2, a: 1 }); // true (order independent)

43

shallow({ a: { x: 1 } }, { a: { x: 1 } }); // false (nested objects)

44

45

// Array comparisons

46

shallow([1, 2, 3], [1, 2, 3]); // true

47

shallow([1, [2, 3]], [1, [2, 3]]); // false (nested arrays)

48

49

// Map comparisons

50

shallow(new Map([["a", 1]]), new Map([["a", 1]])); // true

51

shallow(new Map([["a", 1], ["b", 2]]), new Map([["b", 2], ["a", 1]])); // true

52

53

// Set comparisons

54

shallow(new Set([1, 2]), new Set([1, 2])); // true

55

shallow(new Set([1, 2]), new Set([2, 1])); // true (order independent)

56

57

// Mixed types

58

shallow(null, undefined); // false

59

shallow([], {}); // false

60

```

61

62

### React Shallow Hook

63

64

React hook that provides memoized shallow comparison for optimizing selector functions.

65

66

```typescript { .api }

67

/**

68

* React hook for memoized shallow comparison of selector results

69

* Prevents unnecessary re-renders when selector returns shallowly equal values

70

* @param selector - Function that selects values from state

71

* @returns Memoized selector function

72

*/

73

function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

import { create } from "zustand";

80

import { useShallow } from "zustand/react/shallow";

81

82

const useStore = create((set) => ({

83

user: { name: "John", age: 30 },

84

posts: [],

85

preferences: { theme: "light", lang: "en" },

86

updateUser: (updates) => set((state) => ({

87

user: { ...state.user, ...updates }

88

})),

89

addPost: (post) => set((state) => ({

90

posts: [...state.posts, post]

91

})),

92

}));

93

94

// ❌ Bad - creates new object on every render, causes unnecessary re-renders

95

function UserProfile() {

96

const { user, preferences } = useStore((state) => ({

97

user: state.user,

98

preferences: state.preferences

99

}));

100

101

return <div>{user.name} - {preferences.theme}</div>;

102

}

103

104

// ✅ Good - uses shallow comparison to prevent unnecessary re-renders

105

function UserProfileOptimized() {

106

const { user, preferences } = useStore(

107

useShallow((state) => ({

108

user: state.user,

109

preferences: state.preferences

110

}))

111

);

112

113

return <div>{user.name} - {preferences.theme}</div>;

114

}

115

116

// ✅ Alternative - select individual properties

117

function UserProfileAlternative() {

118

const user = useStore((state) => state.user);

119

const preferences = useStore((state) => state.preferences);

120

121

return <div>{user.name} - {preferences.theme}</div>;

122

}

123

124

// Complex selector with derived state

125

function PostSummary() {

126

const summary = useStore(

127

useShallow((state) => ({

128

totalPosts: state.posts.length,

129

userPosts: state.posts.filter(p => p.authorId === state.user.id),

130

recentPosts: state.posts.slice(-5),

131

}))

132

);

133

134

return (

135

<div>

136

<p>Total: {summary.totalPosts}</p>

137

<p>Yours: {summary.userPosts.length}</p>

138

<p>Recent: {summary.recentPosts.length}</p>

139

</div>

140

);

141

}

142

```

143

144

### Traditional API with Custom Equality

145

146

Alternative store creation and hook APIs that support custom equality functions.

147

148

```typescript { .api }

149

/**

150

* Creates store with default equality function for all selectors

151

* @param initializer - State creator function

152

* @param defaultEqualityFn - Default equality function

153

* @returns Store with equality function support

154

*/

155

function createWithEqualityFn<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(

156

initializer: StateCreator<T, [], Mos>,

157

defaultEqualityFn?: <U>(a: U, b: U) => boolean

158

): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;

159

160

/**

161

* Hook with custom equality function support

162

* @param api - Store API to subscribe to

163

* @returns Complete store state

164

*/

165

function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(

166

api: S

167

): ExtractState<S>;

168

169

/**

170

* Hook with selector and custom equality function

171

* @param api - Store API to subscribe to

172

* @param selector - Function to select specific state slice

173

* @param equalityFn - Custom equality function for comparing values

174

* @returns Selected state slice

175

*/

176

function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(

177

api: S,

178

selector: (state: ExtractState<S>) => U,

179

equalityFn?: (a: U, b: U) => boolean

180

): U;

181

```

182

183

**Usage Examples:**

184

185

```typescript

186

import { createWithEqualityFn, useStoreWithEqualityFn } from "zustand/traditional";

187

import { shallow } from "zustand/shallow";

188

189

// Store with default shallow equality

190

const useStore = createWithEqualityFn(

191

(set) => ({

192

items: [],

193

filters: { category: "all", active: true },

194

addItem: (item) => set((state) => ({

195

items: [...state.items, item]

196

})),

197

updateFilters: (newFilters) => set((state) => ({

198

filters: { ...state.filters, ...newFilters }

199

})),

200

}),

201

shallow // Default equality function for all selectors

202

);

203

204

// Component using default equality

205

function ItemList() {

206

const { items, filters } = useStore(); // Uses shallow comparison

207

208

return (

209

<div>

210

{items

211

.filter(item => filters.category === "all" || item.category === filters.category)

212

.map(item => <div key={item.id}>{item.name}</div>)}

213

</div>

214

);

215

}

216

217

// Component with custom equality function

218

function FilteredItems() {

219

const filteredItems = useStoreWithEqualityFn(

220

useStore,

221

(state) => state.items.filter(item =>

222

state.filters.category === "all" || item.category === state.filters.category

223

),

224

(prevItems, currItems) =>

225

prevItems.length === currItems.length &&

226

prevItems.every((item, i) => item.id === currItems[i].id)

227

);

228

229

return (

230

<div>

231

{filteredItems.map(item => <div key={item.id}>{item.name}</div>)}

232

</div>

233

);

234

}

235

236

// Deep equality for complex objects

237

function UserSettings() {

238

const settings = useStoreWithEqualityFn(

239

useStore,

240

(state) => state.user.settings,

241

(prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)

242

);

243

244

return (

245

<div>

246

<p>Theme: {settings.theme}</p>

247

<p>Language: {settings.language}</p>

248

</div>

249

);

250

}

251

```

252

253

### Performance Optimization Patterns

254

255

Best practices for using utilities to optimize application performance.

256

257

#### Selector Optimization

258

259

```typescript

260

import { create } from "zustand";

261

import { useShallow } from "zustand/react/shallow";

262

263

const useStore = create((set) => ({

264

user: { id: 1, name: "John", email: "john@example.com" },

265

posts: [],

266

comments: [],

267

ui: { loading: false, theme: "light" },

268

// ... actions

269

}));

270

271

// ❌ Avoid - selecting entire state causes re-renders on any change

272

function BadComponent() {

273

const state = useStore();

274

return <div>{state.user.name}</div>;

275

}

276

277

// ❌ Avoid - new object on every render

278

function BadSelectorComponent() {

279

const data = useStore((state) => ({

280

user: state.user,

281

postCount: state.posts.length

282

}));

283

return <div>{data.user.name} has {data.postCount} posts</div>;

284

}

285

286

// ✅ Good - specific property selection

287

function GoodComponent() {

288

const userName = useStore((state) => state.user.name);

289

return <div>{userName}</div>;

290

}

291

292

// ✅ Good - shallow comparison for multiple properties

293

function GoodMultiSelectComponent() {

294

const { user, postCount } = useStore(

295

useShallow((state) => ({

296

user: state.user,

297

postCount: state.posts.length

298

}))

299

);

300

return <div>{user.name} has {postCount} posts</div>;

301

}

302

```

303

304

#### Action Optimization

305

306

```typescript

307

// ✅ Good - separate action selectors to prevent re-renders

308

function OptimizedComponent() {

309

const userName = useStore((state) => state.user.name);

310

const updateUser = useStore((state) => state.updateUser);

311

312

// Actions don't change, so no re-renders from action updates

313

return (

314

<div>

315

<p>{userName}</p>

316

<button onClick={() => updateUser({ name: "Jane" })}>

317

Update Name

318

</button>

319

</div>

320

);

321

}

322

323

// ✅ Alternative - access actions imperatively

324

function ImperativeActionsComponent() {

325

const userName = useStore((state) => state.user.name);

326

327

const handleUpdate = () => {

328

useStore.getState().updateUser({ name: "Jane" });

329

};

330

331

return (

332

<div>

333

<p>{userName}</p>

334

<button onClick={handleUpdate}>Update Name</button>

335

</div>

336

);

337

}

338

```

339

340

#### Custom Equality Functions

341

342

```typescript

343

// Optimized equality functions for different use cases

344

345

// Array comparison by length and key properties

346

const arrayByIds = (prev, curr) =>

347

prev.length === curr.length &&

348

prev.every((item, i) => item.id === curr[i].id);

349

350

// Object comparison by specific properties

351

const userByBasicInfo = (prev, curr) =>

352

prev.id === curr.id &&

353

prev.name === curr.name &&

354

prev.email === curr.email;

355

356

// Date comparison

357

const dateEquality = (prev, curr) =>

358

prev.getTime() === curr.getTime();

359

360

// Usage in components

361

function OptimizedUserList() {

362

const users = useStoreWithEqualityFn(

363

useStore,

364

(state) => state.users,

365

arrayByIds

366

);

367

368

return (

369

<ul>

370

{users.map(user => <li key={user.id}>{user.name}</li>)}

371

</ul>

372

);

373

}

374

```