Immer.js State Library

Immer

Immer provides various functions that allow us to work with javascript objects in an immutable way WITHOUT needing to use the `...props`.

Vanilla JavaScript

Before Immer

const changeName = (person, name) => {
  return { ...person, name };
};

After Immer

import produce from 'immer';

const changeName = (person, name) => {
  return produce(person, draft => {
    draft.name = name;
  });
};

immer's produce(codeoriginalObject, draft => {...})

The first param, person, is the object which you would like to update. The second param is a function that receives a 'draft' version of that argument. The 'draft' object keeps all the properties it has at the beginning, except for those you change draft of the new version, a.k.a., what you want the new version to look like. Immer takes care of all the immutability concerns behind the scenes within the produce() function.

With React

originalState

state = {
    details: { eventName: "Birthday Party" },
    people: [
      { uuid: uuid(), name: "Leigh", attending: true },
      { uuid: uuid(), name: "Pedro", attending: false },
      { uuid: uuid(), name: "Dorothy", attending: false },
      { uuid: uuid(), name: "Grandma", attending: true }
    ]
  };

Before Immer

setEventName = value => {
  const { details } = this.state;
  this.setState({
    details: { ...details, eventName: value }
  });
};

After Immer

setEventName = value => {
  this.setState(
    produce(draft => {
      draft.details.eventName = value;
    })
  );
};
When you pass a function as the first param to ` produce() `, it returns a function, which then gets passed to ` setState() `. prevState shown below gets passed into ` produce() ` as draft. Which gives you access to all the previous values in state and allowing you to mutate (in an immutable way) the state object.
toggleShouldShow = () => {
  // prevState gets passed as draft into produce()
  this.setState(prevState => {
    // do stuff
    // return new state after doing stuff
  });
};

More React Examples

Before Immer

updateAttending = (uuid, newAttending) => {
  const { people } = this.state;
  const newPeople = people.map(person => {
    if (person.uuid === uuid) {
      return { ...person, attending: newAttending };
    }
    return person;
  });
  this.setState({
    people: newPeople
  });
};

After Immer

updateAttending = (uuid, newAttending) => {
  this.setState(
    produce(draft => {
      draft.people.forEach(person => {
        if (person.uuid === uuid) {
          person.attending = newAttending;
        }
      });
    })
  );
};

Before Immer

removePerson = uuid => {
  const { people } = this.state;
  const newPeople = people.filter(person => person.uuid !== uuid);
  this.setState({
    people: newPeople
  });
};

After Immer

removePerson = uuid => {
  this.setState(produce(draft => {
    draft.people = people.filter(person => person.uuid !== uuid);
  }));
};
arrow_back

Previous

JavaScript Tricks

Next

Class Syntax
arrow_forward