Skip to content

React Immer State Update

DodaTech 2 min read

In this tutorial, you'll learn about React Immer State Update Error Fix. We cover key concepts, practical examples, and best practices.

The Problem

Updating nested state in React creates verbose, error-prone code.

Wrong

const [state, setState] = useState({
  user: { name: 'John', address: { city: 'NYC', zip: '10001' } },
  posts: [{ id: 1, title: 'Post 1' }],
})

// Updating nested property — verbose and easy to make mistakes
setState(prev => ({
  ...prev,
  user: {
    ...prev.user,
    address: {
      ...prev.user.address,
      city: 'Brooklyn',
    },
  },
}))

Output: works but the spread operator pattern is error-prone with deep nesting.

Use Immer with useImmer:

npm install immer use-immer
import { useImmer } from 'use-immer'

function App() {
  const [state, updateState] = useImmer({
    user: { name: 'John', address: { city: 'NYC', zip: '10001' } },
    posts: [{ id: 1, title: 'Post 1' }],
  })

  const updateCity = () => {
    updateState(draft => {
      draft.user.address.city = 'Brooklyn'
    })
  }

  const addPost = () => {
    updateState(draft => {
      draft.posts.push({ id: Date.now(), title: 'New Post' })
    })
  }

  return <div>
    <p>{state.user.address.city}</p>
    <button onClick={updateCity}>Update City</button>
    <button onClick={addPost}>Add Post</button>
  </div>
}

Expected output: city updates to Brooklyn and new post is added without spread operators.

Prevention

  • Use Immer with useImmer hook for complex state shapes
  • Use Immer's produce function directly in setState callbacks
  • Keep state as flat as possible to minimize nesting

Common Mistakes with immer state update

  1. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  2. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  3. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks

These mistakes appear frequently in real-world REACT code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What does Immer do?

Immer creates a draft copy of your state that you can mutate directly. It tracks mutations and produces an immutable state update automatically.

Can I use Immer with useReducer?

Yes. Wrap your reducer with Immer's produce: const reducer = produce((draft, action) => { ... }). The reducer can safely mutate the draft.

No. For simple state (primitives, flat objects), plain useState is sufficient. Immer adds value for deeply nested state or frequent array mutations.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro