useImmer – A React Hook to use Immer to manipulate state

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, in which the draft can be mutated freely, until the producer ends and the changes will be made immutable and become the next state.

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>
  );
}

Also comes with an useImmerReducer Hook.

use-immer →

Related: The previously linked Mutik also uses Immer under the hood.

Mutik – A tiny immutable state management library based on Immer

Nice work by Jared Palmer: a React State Management Library which uses Immer internally so you don’t have to worry about overwriting (unrelated) parts of your state whilst updating some value in it.

import React from 'react';
import { render } from 'react-dom';
import { createStore, Provider, useSelector } from 'mutik';
 
// Create a lil' store with some state
let store = createStore({
  count: 0,
});
 
// Pass the store to the Provider.
function App() {
  return (
    <Provider store={store}>
      <div>
        <Label />
        <Buttons />
      </div>
    </Provider>
  );
}
 
// You can mutate the store from anywhere you want to,
// even outside of React code. Mutate is based on immer.
function increment() {
  store.mutate(state => {
    state.count++;
  });
}
 
// Or you can update it like React.useState's update
function decrement() {
  store.set(prevState => ({
    ...state,
    count: state.count - 1
  });
}
 
// You don't need to pass it down as props either,
// although you can if you need to.
function Buttons() {
  return (
    <React.Fragment>
      <button onClick={decrement}>-</button>
      <button onClick={increment}>+</button>
    </React.Fragment>
  );
}
 
function Label() {
  // You can subcribe to "slices" of mutable state with useSelector
  // Note: be sure to memoize these with React.useCallback
  const selector = React.useCallback(state => state.count, []);
  const count = useSelector(selector);
  return <p>The count is {count}</p>;
}
 
render(<App />, window.root);

As you can see in the code example you can use store.set or leverage its power by calling store.mutate which takes an Immer-style updater function as its argument.

Installation per npm/Yarn

yarn add mutik

Mutik Source (GitHub) →
Mutik Demo →

⚠️ Mutik requires experimental builds of react/react-dom as it used the brand spanking new useMutableSource hook which landed only 5 days ago!

yarn add [email protected] [email protected]