This is the 28th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Translate: beta.reactjs.org/learn/updat…

State can hold any type of JavaScript value, including objects. But you shouldn’t directly change the objects you hold in React State. Instead, when you want to update an object, you need to create a new object (or copy an existing one) and then set state to use that copy.

Update nested objects – old way of writing

Consider a nested object structure like this:

const [person, setPerson] = useState({
  name: 'Niki de Saint Phalle'.artwork: {
    title: 'Blue Nana'.city: 'Hamburg'.image: 'https://i.imgur.com/Sd1AgUOm.jpg',}});Copy the code

If you want to update Person.artwork. City, you know how to do it directly:

But in React, you need to treat states as immutable! To change the City, you first need to generate a new Artwork object (pre-populated with data from the previous one) and then generate a new Person object pointing to the new artwork:

constnextArtwork = { ... person.artwork,city: 'New Delhi' };
constnextPerson = { ... person,artwork: nextArtwork };
setPerson(nextPerson);
Copy the code

Or, as a single function call:

setPerson({ ... person,// Copy other fields
  artwork: { // but replace the artwork. person.artwork,// with the same one
    city: 'New Delhi' // but in New Delhi!}});Copy the code

Write concise update logic using IMmer

If your state is deeply nested, you may want to consider flattening it. But if you don’t want to change the structure of state, you prefer to use the nested extension shortcut. Immer is a popular library that allows you to write code using a convenient but constantly changing syntax and takes care of making copies for you. With immer, you write code that looks like you’re “breaking the rules” and changing an object:

updatePerson(draft= > {
  draft.artwork.city = 'Lagos';
});
Copy the code

But unlike regular mutations, it doesn’t overwrite past states!

Try Immer:

  • willuse-immerAdd as a dependency to yourspackage.json
  • performnpm install
  • thenimport { useState } from 'react'Replace withimport { useImmer } from 'use-immer'
import { useImmer } from 'use-immer';

export default function Form() {
  const [person, updatePerson] = useImmer({
    name: 'Niki de Saint Phalle'.artwork: {
      title: 'Blue Nana'.city: 'Hamburg'.image: 'https://i.imgur.com/Sd1AgUOm.jpg',}});function handleNameChange(e) {
    updatePerson(draft= > {
      draft.name = e.target.value;
    });
  }

  function handleTitleChange(e) {
    updatePerson(draft= > {
      draft.artwork.title = e.target.value;
    });
  }

  function handleCityChange(e) {
    updatePerson(draft= > {
      draft.artwork.city = e.target.value;
    });
  }

  function handleImageChange(e) {
    updatePerson(draft= > {
      draft.artwork.image = e.target.value;
    });
  }

  return (
    <>
      <label>
        Name:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Title:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        City:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' by '}
        {person.name}
        <br />
        (located in {person.artwork.city})
      </p>
      <img 
        src={person.artwork.image} 
        alt={person.artwork.title}
      />
    </>
  );
}
Copy the code

Notice how concise the event handlers have become. You can mix useState and useImmer in a single component as needed. Immer is a good way to keep update handlers concise, especially if you have nesting in your state and copying objects results in duplicate code.

How does Immer work?

Draft, provided by Immer, is a special type of object called a Proxy that “records” what you do with it. That’s why you can modify it as much as you want! Immer finds out which parts of the draft have changed and generates a brand new object containing your edits.