React 공식문서 이해하기 (15)

Syoee·2023년 11월 23일
0

React

목록 보기
15/30
post-thumbnail

Chapter 2. Adding Interactivity

#7 배열 state 업데이트

학습 목차

1. 변이 없이 배열 업데이트하기
2. 배열 내부의 객체 업데이트하기


1. 변이 없이 배열 업데이트하기

  • JavaScript에서 배열은 객체의 또 다른 종류일 뿐이다.

  • 객체와 마찬가지로, React state의 배열은 읽기 전용으로 취급해야 한다.
    즉, arr[0] = 'bird'와 같이 배열 내부의 항목을 재할당해서는 안 되며, push()pop()과 같이 배열을 변이하는 메서드도 사용해서는 안된다.

  • 대신 배열을 업데이트할 때마다 state 설정 함수에 새 배열을 전달하고 싶을 것이다.
    그렇게 하려면 state의 원래 배열에서 filter()map()과 같은 비변이 메서드를 호출하여 새 배열을 만들면 된다.
    그렇게 만들어진 새 배열을 state로 설정할 수 있다.

  • React state 내에서 배열을 다룰 때는 왼쪽 열의 메서드를 피하고 대신 오른쪽 열의 메서드를 선호해야 한다.

비추천 (배열 직접 변이)추천 (새 배열 반환)
추가push, unshiftconcat, [...arr] spread syntax (example)
삭제pop, shift, splicefilter, slice (example)
교체splice, arr[i] = ... assignmentmap (example)
정렬reverse, sort배열을 복사한 다음 처리(example)
  • 또는 두 열의 메서드를 모두 사용할 수 있는 Immer를 사용할 수도 있다.

!주의!

  • slice와 splice는 이름이 비슷하지만 매우 다르다.
    • slice는 배열 또는 배열의 일부를 복사할 수 있습니다.
    • splice는 배열을 항목을 삽입하거나 삭제하기 위해 변이 합니다.
  • React에서는 state의 객체나 배열을 변이하고 싶지 않기 때문에 slice를 훨씬 더 자주 사용하게 될 것이다.
  • 객체 state 업데이트에서 변이가 무엇이고 왜 state에 권장되지 않는지에 대해 설명한다.

1-1. 배열에 추가하기

  • push()는 배열을 변이한다.
import { useState } from 'react';

let nextId = 0;

export default function List() {
  const [name, setName] = useState('');
  const [artists, setArtists] = useState([]);

  return (
    <>
      <h1>Inspiring sculptors:</h1>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <button onClick={() => {
        setArtists([
          ...artists,
          { id: nextId++, name: name }
        ]);
      }}>Add</button>
      <ul>
        {artists.map(artist => (
          <li key={artist.id}>{artist.name}</li>
        ))}
      </ul>
    </>
  );
}
  • 배열 전개 구문을 사용하면 항목을 원본 배열 ...artists 앞에 배치하여 항목을 추가할 수도 있다.
setArtists([
  { id: nextId++, name: name },
  ...artists // Put old items at the end
]);
  • 이런 식으로 전개 구문은 배열의 끝에 추가하는 push()와 배열의 시작 부분에 추가하는unshift()의 기능을 모두 수행할 수 있다.

1-2. 배열에서 제거하기

  • 배열에서 항목을 제거하는 가장 쉬운 방법은 필터링하는 것입니다. 즉, 해당 항목을 포함하지 않는 새 배열을 생성한다.
    이렇게 하려면 filter 메서드를 사용할 수 있다.
setArtists(
  artists.filter(a => a.id !== artist.id)
);
  • artists.filter(a => a.id !== artist.id)구문은 artist.id와 다른 ID를 가진 artists로 구성된 배열을 생성한다”는 의미이다.
    즉, 각 아티스트의 ‘삭제’ 버튼은 배열에서 해당 아티스트를 필터링한 다음 결과 배열로 다시 렌더링하도록 요청한다.
    filter는 원래 배열을 수정하지 않는다는 점에 유의하자.

1-3. 배열 변경하기

  • 배열의 일부 또는 모든 항목을 변경하려면 map()을 사용하여 새로운 배열을 만들 수 있다.
    map에 전달할 함수는 데이터 또는 인덱스(또는 둘 다)에 따라 각 항목에 대해 수행할 작업을 결정할 수 있다.

1-4. 배열에서 항목 교체하기

  • 배열에서 하나 이상의 항목을 바꾸고 싶은 경우가 특히 흔하다.
    ar[0] = 'bird'와 같은 할당은 원래 배열을 변이하는 것이므로 이 경우에도 map을 사용하는 것이 좋다.

1-5. 배열에 삽입하기

  • 때로는 시작도 끝도 아닌 특정 위치에 항목을 삽입하고 싶을 때가 있다.
    이를 위해 ... 배열 전개 구문과 slice() 메서드를 함께 사용할 수 있다.
    slice() 메서드를 사용하면 배열의 “조각”을 잘라낼 수 있다.
    항목을 삽입하려면 삽입 지점 앞에 slicespread한 다음 새 항목과 나머지 원래 배열을 펼치는 배열을 만든다.

1-6. 배열에 다른 변경 사항 적용하기

  • 전개 구문과 map()filter()와 같은 비변이 메서드만으로는 할 수 없는 일이 몇 가지 있다.
    예를 들어, 배열을 반전시키거나 정렬하고 싶을 수 있다.
    JavaScript reverse()sort() 메서드는 원래 배열을 변이하므로 직접 사용할 수 없다.

  • 대신, 배열을 먼저 복사한 다음 변이하면 된다.

  • 배열을 복사하더라도 배열 내부의 기존 항목을 직접 변이할 수는 없다.
    이는 얕은 복사가 이루어져 새 배열에는 원래 배열과 동일한 항목이 포함되기 때문이다.
    따라서 복사된 배열 내부의 객체를 수정하면 기존 state를 변이하는 것이다.
    예를 들어, 다음과 같은 코드가 문제가 됩니다.

const nextList = [...list];
nextList[0].seen = true; // Problem: mutates list[0]
setList(nextList);
  • nextListlist는 서로 다른 배열이지만, nextList[0]list[0]은 같은 객체를 가리킨다.
    따라서 nextList[0].seen을 변경하면 list[0].seen도 변경하는 것이다.
    이것은 state를 변이하므로 피해야 한다.
    중첩된 JavaScript 객체 업데이트와 비슷한 방법으로 이 문제를 해결할 수 있는데, 변경하려는 개별 항목을 변이하는 대신 복사하는 것이다.

2. 배열 내부의 객체 업데이트하기

  • 객체는 실제로 배열 “내부”에 위치하지 않는다.
  • 코드에서는 “내부”에 있는 것처럼 보일 수 있지만 배열의 각 객체는 배열이 “가리키는” 별도의 값이다.
    그렇기 때문에 list[0]과 같이 중첩된 필드를 변경할 때 주의해야 한다.
  • 다른 사람의 작품 목록이 배열의 동일한 요소를 가리킬 수 있다.
  • 중첩된 state를 업데이트할 때는 업데이트하려는 지점부터 최상위 수준까지 복사본을 만들어야 한다.

2-1. Immer로 간결한 업데이트 로직 작성하기

  • 중첩 배열을 변이 없이 업데이트하는 작업은 객체를 다룰 때와 같이 약간 반복적일 수 있다.
    • 일반적으로 state를 몇 레벨 이상 깊이 업데이트할 필요는 없다.
      state 객체가 매우 깊다면 다르게 재구성하여 평평하게 만드는 것이 좋다.
    • state 구조를 변경하고 싶지 않다면, Immer는 변이 구문을 사용하여 작성하더라도 자동으로 사본 생성을 처리해 주어 편리하다.

요약

  • 배열을 state에 넣을 수는 있지만 변경할 수는 없다.
  • 배열을 변이하는 대신 배열의 새로운 버전을 생성하고 state를 업데이트하라.
  • 배열 전개 구문 [...arr, newItem]을 사용하여 새 항목으로 배열을 만들 수 있다.
  • filter()map()을 사용하여 필터링되거나 변형된 항목으로 새 배열을 만들 수 있다.
  • Immer를 사용하면 코드를 간결하게 유지할 수 있다.

React 공식 문서

https://react.dev/

React 비공식 번역 문서

https://react-ko.dev/

MDN

https://developer.mozilla.org/ko/

Wikipedia

https://ko.wikipedia.org/wiki/

profile
함께 일하고 싶어지는 동료, 프론트엔드 개발자입니다.

0개의 댓글

관련 채용 정보