Convert Figma logo to code with AI

immerjs logouse-immer

Use immer to drive state with a React hooks

4,127
98
4,127
7

Top Related Projects

The official, opinionated, batteries-included toolset for efficient Redux development

48,653

🐻 Bear necessities for state management in React

27,618

Simple, scalable state management.

18,501

👻 Primitive and flexible state management for React

Quick Overview

use-immer is a React hook that simplifies state management by allowing you to mutate state directly using the Immer library. It provides an intuitive way to update complex nested state structures while maintaining immutability under the hood.

Pros

  • Simplifies state updates for complex nested objects
  • Reduces boilerplate code compared to traditional React state management
  • Maintains immutability while allowing seemingly mutable operations
  • Integrates seamlessly with React's useState hook

Cons

  • Adds an additional dependency to your project
  • May have a slight performance overhead for very simple state updates
  • Learning curve for developers unfamiliar with Immer's concepts
  • Potential overuse might lead to less explicit state management

Code Examples

  1. Basic usage with a simple object:
import { useImmer } from "use-immer";

function Counter() {
  const [state, setState] = useImmer({ count: 0 });

  const increment = () => {
    setState(draft => {
      draft.count += 1;
    });
  };

  return <button onClick={increment}>{state.count}</button>;
}
  1. Updating nested state:
import { useImmer } from "use-immer";

function UserProfile() {
  const [user, updateUser] = useImmer({
    name: "John",
    address: { city: "New York", country: "USA" }
  });

  const updateCity = newCity => {
    updateUser(draft => {
      draft.address.city = newCity;
    });
  };

  return (
    <div>
      <p>{user.name} lives in {user.address.city}</p>
      <button onClick={() => updateCity("Los Angeles")}>Move to LA</button>
    </div>
  );
}
  1. Working with arrays:
import { useImmer } from "use-immer";

function TodoList() {
  const [todos, updateTodos] = useImmer([
    { id: 1, text: "Learn React", done: false },
    { id: 2, text: "Try use-immer", done: false }
  ]);

  const toggleTodo = id => {
    updateTodos(draft => {
      const todo = draft.find(t => t.id === id);
      todo.done = !todo.done;
    });
  };

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id} onClick={() => toggleTodo(todo.id)}>
          {todo.text} - {todo.done ? "Done" : "Not done"}
        </li>
      ))}
    </ul>
  );
}

Getting Started

To start using use-immer in your React project:

  1. Install the package:

    npm install use-immer
    
  2. Import and use the hook in your component:

    import { useImmer } from "use-immer";
    
    function MyComponent() {
      const [state, setState] = useImmer(initialState);
    
      // Use setState to update state
      const updateState = () => {
        setState(draft => {
          // Mutate draft directly
        });
      };
    
      return (
        // Your JSX here
      );
    }
    

Competitor Comparisons

The official, opinionated, batteries-included toolset for efficient Redux development

Pros of Redux Toolkit

  • Provides a more comprehensive state management solution with built-in tools for async operations and middleware
  • Includes utilities for creating and managing slices of state, reducing boilerplate code
  • Offers better integration with Redux DevTools for debugging and time-travel debugging

Cons of Redux Toolkit

  • Steeper learning curve due to its more complex architecture and concepts
  • Requires more setup and configuration compared to use-immer's simplicity
  • Can be overkill for smaller applications or simpler state management needs

Code Comparison

Redux Toolkit:

import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: state => state + 1,
  },
});

use-immer:

import { useImmer } from 'use-immer';

const [count, setCount] = useImmer(0);
const increment = () => setCount(draft => draft + 1);

Summary

Redux Toolkit offers a more robust state management solution with additional features and tools, making it suitable for larger applications with complex state requirements. However, it comes with a steeper learning curve and more setup overhead. use-immer, on the other hand, provides a simpler approach to state management, focusing on immutable updates with less boilerplate, making it ideal for smaller projects or components that require localized state management.

48,653

🐻 Bear necessities for state management in React

Pros of zustand

  • Lightweight and minimalistic, with a smaller bundle size
  • Supports middleware and devtools out of the box
  • Can be used outside of React components

Cons of zustand

  • Less intuitive for managing complex nested state
  • Doesn't provide built-in immutability guarantees
  • Requires more boilerplate for larger applications

Code Comparison

zustand:

import create from 'zustand'

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
}))

use-immer:

import { useImmer } from 'use-immer'

const [state, setState] = useImmer({ count: 0 })
const increment = () => setState(draft => { draft.count++ })

Key Differences

  • zustand uses a single store approach, while use-immer is typically used with React's useState
  • use-immer provides a more intuitive API for updating nested state
  • zustand offers more flexibility in terms of where and how the store can be accessed

Use Cases

  • zustand: Best for applications requiring global state management with minimal setup
  • use-immer: Ideal for components with complex, nested state that benefit from immutable updates
27,618

Simple, scalable state management.

Pros of MobX

  • More comprehensive state management solution with built-in reactivity
  • Supports complex scenarios and large-scale applications
  • Offers automatic tracking of observables and computed values

Cons of MobX

  • Steeper learning curve due to its more complex API
  • Requires more boilerplate code for setup and configuration
  • Can lead to less predictable behavior in some cases

Code Comparison

MobX:

import { makeObservable, observable, action } from "mobx";

class TodoStore {
  todos = [];

  constructor() {
    makeObservable(this, {
      todos: observable,
      addTodo: action
    });
  }

  addTodo(text) {
    this.todos.push({ text, completed: false });
  }
}

use-immer:

import { useImmer } from "use-immer";

function TodoList() {
  const [todos, updateTodos] = useImmer([]);

  const addTodo = (text) => {
    updateTodos((draft) => {
      draft.push({ text, completed: false });
    });
  };

  // ...
}

use-immer provides a simpler API for immutable state updates, making it easier to use and understand for smaller applications or components. MobX offers a more powerful and flexible solution for complex state management needs but requires more setup and knowledge to use effectively.

18,501

👻 Primitive and flexible state management for React

Pros of Jotai

  • Lightweight and minimalistic, with a smaller bundle size
  • Supports atomic state management, allowing for fine-grained updates
  • Built-in support for async state and derived state

Cons of Jotai

  • Steeper learning curve for developers familiar with Redux-like patterns
  • Less established ecosystem compared to Immer

Code Comparison

use-immer:

import { useImmer } from "use-immer";

const [state, setState] = useImmer({ count: 0 });
setState(draft => { draft.count += 1 });

Jotai:

import { atom, useAtom } from "jotai";

const countAtom = atom(0);
const [count, setCount] = useAtom(countAtom);
setCount(prev => prev + 1);

Both libraries aim to simplify state management in React applications, but they take different approaches. use-immer focuses on providing immutable state updates using Immer's draft concept, while Jotai emphasizes atomic state management with a more flexible API. use-immer may be more intuitive for developers accustomed to working with immutable data structures, while Jotai offers a more granular approach to state management that can be beneficial for complex applications with interdependent state.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

use-immer

A hook to use immer as a React hook to manipulate state.

Installation

npm install immer use-immer

API

useImmer

useImmer(initialState) is very similar to useState. The function returns a tuple, the first value of the tuple is the current state, the second is the updater function, which accepts an immer producer function or a value as argument.

Managing state with immer producer function

When passing a function to the updater, the draft argument can be mutated freely, until the producer ends and the changes will be made immutable and become the next state.

Example: https://codesandbox.io/s/l97yrzw8ol

import React from "react";
import { useImmer } from "use-immer";


function App() {
  const [person, updatePerson] = useImmer({
    name: "Michel",
    age: 33
  });

  function updateName(name) {
    updatePerson(draft => {
      draft.name = name;
    });
  }

  function becomeOlder() {
    updatePerson(draft => {
      draft.age++;
    });
  }

  return (
    <div className="App">
      <h1>
        Hello {person.name} ({person.age})
      </h1>
      <input
        onChange={e => {
          updateName(e.target.value);
        }}
        value={person.name}
      />
      <br />
      <button onClick={becomeOlder}>Older</button>
    </div>
  );
}

(obviously, immer is a little overkill for this example)

Managing state as simple useState hook

When passing a value to the updater instead of a function, useImmer hook behaves the same as useState hook and updates the state with that value.

import React from 'react';
import { useImmer } from 'use-immer';

function BirthDayCelebrator(){
  const [age, setAge] = useImmer(20);

  function birthDay(event){
    setAge(age + 1);
    alert(`Happy birthday #${age} Anon! hope you good`);
  }

  return(
    <div>
      <button onClick={birthDay}>It is my birthday</button>
    </div>
  );
}

Obviously if you have to deal with immutability it is better option passing a function to the updater instead of a direct value.

useImmerReducer

Immer powered reducer, based on useReducer hook

Example: https://codesandbox.io/s/2zor1monvp

import React from "react";
import { useImmerReducer } from "use-immer";

const initialState = { count: 0 };

function reducer(draft, action) {
  switch (action.type) {
    case "reset":
      return initialState;
    case "increment":
      return void draft.count++;
    case "decrement":
      return void draft.count--;
  }
}

function Counter() {
  const [state, dispatch] = useImmerReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  );
}

NPM DownloadsLast 30 Days