LEARN REACT_ ADDING INTERACTIVITY_ Updating Objects in State

서정준·2023년 7월 3일
0

react.dev

목록 보기
5/5

출처: React doc

Updating a nested object

in React, you treat state as immutable!

So far you’ve been working with numbers, strings, and booleans. These kinds of JavaScript values are “immutable”, meaning unchangeable or “read-only”. You can trigger a re-render to replace a value:

Now consider an object in state:

const [position, setPosition] = useState({ x: 0, y: 0 });

Technically, it is possible to change the contents of the object itself. This is called a mutation:

position.x = 5;

However, although objects in React state are technically mutable, you should treat them as if they were immutable—like numbers, booleans, and strings. Instead of mutating them, you should always replace them.

In other words, you should treat any JavaScript object that you put into state as read-only.

But without using the state setting function, React has no idea that object has changed.

👉 이론적으로 object는 mutable할 수 있지만, immutabl을 지켜줘야 한다. 즉, object를 update할 시 불변성을 지켜줘야한다. 우리가 아래의 코드와 같이 let을 안쓰고 const를 쓰는 이유는 react의 불변성을 나타내기 위함이다.

const [name, setName] = useState('jun')

Copying objects with the spread syntax

... spread syntax is “shallow”—it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you’ll have to use it more than once.

👉 spread syntax는 one level만 복사한다. two level로 들어가는 순간 얕은 복사가 이루어진다.

[
	student { // one level
    	age: 20, // two level
        weight: 50,
        
]

Updating a nested object

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

위와 같이 중첩된 object일 경우 아래와 같이 state 값을 변경할 수 있다.

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

아래와 같이 작성해도 얕은 복사로 인해 state가 업데이트가 되지만 불변성을 지켜주기 위해 우리는 위와 같이 state를 업데이트 해줘야 한다.

person.artwork.city = 'New Delhi';
setPerson({...person}});

※ 얕은 복사를 해도 state값이 변경되는 이유는?
https://velog.io/@tree0787/shallow-and-deep-copy

Write concise update logic with Immer

immer
If your state is deeply nested, you might want to consider flattening it. But, if you don’t want to change your state structure, you might prefer a shortcut to nested spreads.

To try Immer:

Run npm install use-immer to add Immer as a dependency
Then replace import { useState } from 'react' with import { useImmer } from 'use-immer'
Here is the above example converted to 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}
      />
    </>
  );
}

👉 spread연산자가 쓰기 번거러울 때는 immer

profile
통통통통

0개의 댓글