or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Use Immer

1

2

Use Immer provides React hooks that integrate immer for immutable state management. It enables developers to write state updates using familiar mutable syntax while maintaining React's immutability requirements, making complex state transformations more readable and less error-prone.

3

4

## Package Information

5

6

- **Package Name**: use-immer

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install immer use-immer`

10

11

## Core Imports

12

13

```typescript

14

import { useImmer, useImmerReducer } from "use-immer";

15

```

16

17

CommonJS:

18

19

```javascript

20

const { useImmer, useImmerReducer } = require("use-immer");

21

```

22

23

Import individual types:

24

25

```typescript

26

import { useImmer, useImmerReducer, type DraftFunction, type ImmerHook, type ImmerReducer } from "use-immer";

27

```

28

29

Import external types used in API signatures:

30

31

```typescript

32

import type { Draft } from "immer";

33

import type { Dispatch } from "react";

34

```

35

36

## Basic Usage

37

38

```typescript

39

import React from "react";

40

import { useImmer } from "use-immer";

41

42

function PersonEditor() {

43

const [person, updatePerson] = useImmer({

44

name: "Michel",

45

age: 33,

46

address: {

47

city: "Amsterdam",

48

country: "Netherlands"

49

}

50

});

51

52

function updateName(name: string) {

53

updatePerson(draft => {

54

draft.name = name;

55

});

56

}

57

58

function moveToCity(city: string) {

59

updatePerson(draft => {

60

draft.address.city = city;

61

});

62

}

63

64

return (

65

<div>

66

<h1>{person.name} ({person.age})</h1>

67

<p>Lives in {person.address.city}, {person.address.country}</p>

68

<input

69

value={person.name}

70

onChange={e => updateName(e.target.value)}

71

/>

72

</div>

73

);

74

}

75

```

76

77

## Capabilities

78

79

### State Hook with Immer Integration

80

81

React hook similar to useState but allows mutating a draft state using immer producer functions.

82

83

```typescript { .api }

84

/**

85

* React hook similar to useState but with immer integration for immutable updates

86

* @param initialValue - Initial state value or function that returns initial state

87

* @returns Tuple of [currentState, updaterFunction]

88

*/

89

function useImmer<S = any>(initialValue: S | (() => S)): ImmerHook<S>;

90

91

type ImmerHook<S> = [S, Updater<S>];

92

93

type Updater<S> = (arg: S | DraftFunction<S>) => void;

94

95

type DraftFunction<S> = (draft: Draft<S>) => void;

96

```

97

98

The `useImmer` hook accepts either a direct value or a producer function that receives a mutable draft:

99

100

**Usage Examples:**

101

102

```typescript

103

import { useImmer } from "use-immer";

104

105

// Direct value updates (like useState)

106

const [count, setCount] = useImmer(0);

107

setCount(count + 1);

108

109

// Draft function updates (using immer)

110

const [user, updateUser] = useImmer({ name: "Alice", posts: [] });

111

updateUser(draft => {

112

draft.posts.push({ title: "New Post", content: "..." });

113

});

114

115

// Lazy initial state

116

const [expensiveState, updateExpensiveState] = useImmer(() => computeExpensiveInitialState());

117

```

118

119

### Reducer Hook with Immer Integration

120

121

Immer-powered reducer hook based on React's useReducer, allowing reducers to mutate draft state.

122

123

```typescript { .api }

124

/**

125

* Immer-powered reducer hook that allows reducers to mutate draft state

126

* @param reducer - Reducer function that operates on draft state

127

* @param initialState - Initial state value

128

* @returns Tuple of [state, dispatch]

129

*/

130

function useImmerReducer<S, A>(

131

reducer: ImmerReducer<S, A>,

132

initialState: S,

133

initializer?: undefined

134

): [S, Dispatch<A>];

135

136

/**

137

* Immer-powered reducer hook with initializer function

138

* @param reducer - Reducer function that operates on draft state

139

* @param initializerArg - Argument passed to initializer function

140

* @param initializer - Function to compute initial state

141

* @returns Tuple of [state, dispatch]

142

*/

143

function useImmerReducer<S, A, I>(

144

reducer: ImmerReducer<S, A>,

145

initializerArg: I,

146

initializer: (arg: I) => S

147

): [S, Dispatch<A>];

148

149

/**

150

* Immer-powered reducer hook with typed initializer argument

151

* @param reducer - Reducer function that operates on draft state

152

* @param initializerArg - Typed argument passed to initializer function

153

* @param initializer - Function to compute initial state from typed argument

154

* @returns Tuple of [state, dispatch]

155

*/

156

function useImmerReducer<S, A, I>(

157

reducer: ImmerReducer<S, A>,

158

initializerArg: S & I,

159

initializer: (arg: S & I) => S

160

): [S, Dispatch<A>];

161

162

type ImmerReducer<S, A> = (

163

draftState: Draft<S>,

164

action: A

165

) => void | (S extends undefined ? typeof nothing : S);

166

```

167

168

**Usage Examples:**

169

170

```typescript

171

import { useImmerReducer } from "use-immer";

172

173

// Define reducer that mutates draft state

174

function counterReducer(draft, action) {

175

switch (action.type) {

176

case "increment":

177

draft.count++;

178

break;

179

case "decrement":

180

draft.count--;

181

break;

182

case "reset":

183

return { count: 0 }; // Can still return new state

184

}

185

}

186

187

function Counter() {

188

const [state, dispatch] = useImmerReducer(counterReducer, { count: 0 });

189

190

return (

191

<div>

192

Count: {state.count}

193

<button onClick={() => dispatch({ type: "increment" })}>+</button>

194

<button onClick={() => dispatch({ type: "decrement" })}>-</button>

195

<button onClick={() => dispatch({ type: "reset" })}>Reset</button>

196

</div>

197

);

198

}

199

200

// Complex state example

201

interface TodoState {

202

todos: Array<{ id: number; text: string; completed: boolean }>;

203

filter: "all" | "active" | "completed";

204

}

205

206

function todoReducer(draft: TodoState, action: any) {

207

switch (action.type) {

208

case "add_todo":

209

draft.todos.push({

210

id: Date.now(),

211

text: action.text,

212

completed: false

213

});

214

break;

215

case "toggle_todo":

216

const todo = draft.todos.find(t => t.id === action.id);

217

if (todo) {

218

todo.completed = !todo.completed;

219

}

220

break;

221

case "set_filter":

222

draft.filter = action.filter;

223

break;

224

}

225

}

226

```

227

228

## Types

229

230

```typescript { .api }

231

/**

232

* Function type for immer draft manipulation

233

*/

234

type DraftFunction<S> = (draft: Draft<S>) => void;

235

236

/**

237

* Updater function that accepts either a value or a draft function

238

* When passed a function, it's treated as a draft function and passed to immer's produce

239

* When passed a value, it replaces the state directly (like useState)

240

*/

241

type Updater<S> = (arg: S | DraftFunction<S>) => void;

242

243

/**

244

* Return type for useImmer hook - tuple of state and updater

245

*/

246

type ImmerHook<S> = [S, Updater<S>];

247

248

/**

249

* Reducer function type that operates on immer draft state

250

*/

251

type ImmerReducer<S, A> = (

252

draftState: Draft<S>,

253

action: A

254

) => void | (S extends undefined ? typeof nothing : S);

255

256

/**

257

* @deprecated Use ImmerReducer instead since there is already a Reducer type in @types/react

258

*/

259

type Reducer<S = any, A = any> = ImmerReducer<S, A>;

260

```

261

262

### External Types Referenced

263

264

These types are imported from external dependencies and used in the API signatures:

265

266

```typescript { .api }

267

/**

268

* From immer: Mutable proxy type for immutable state updates

269

*/

270

type Draft<T> = T; // Immer's Draft type - provides mutable interface to immutable data

271

272

/**

273

* From immer: Sentinel value for indicating deletion in draft operations

274

*/

275

const nothing: unique symbol;

276

277

/**

278

* From react: Dispatch function type for useReducer hook

279

*/

280

type Dispatch<A> = (value: A) => void;

281

```

282

283

## Dependencies

284

285

This package requires the following peer dependencies:

286

287

- **immer**: `>=8.0.0` - Core immer functionality for immutable updates

288

- **react**: `^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0` - React hooks support

289

290

The following immer types and functions are re-exported and used internally:

291

292

- `Draft<T>` - Immer draft type for mutable state proxies

293

- `nothing` - Immer sentinel value for indicating deletion

294

- `freeze` - Immer function for creating immutable objects

295

- `produce` - Immer function for creating new state from mutations

296

297

## Error Handling

298

299

The hooks follow React's error handling patterns:

300

301

- Invalid initial state will throw during component initialization

302

- Errors in draft functions are propagated as React errors

303

- Type errors occur at compile time when using TypeScript with proper typings