상태의 배열 업데이트하기
상태의 배열 업데이트하기
배열도 상태에 넣을 수 있어요. 다만 객체와 마찬가지로 배열을 상태에 넣으면 그 배열을 바꿀 수 없어요. 배열을 업데이트하고 싶다면 새 배열을 만들어 상태 설정 함수에 전달해야 해요. 이 글에서는 배열의 추가·제거·정렬·중첩 객체 업데이트를 어떻게 안전하게 다루는지 정리할게요.
배열을 변형하지 않고 업데이트하기
배열을 업데이트할 때마다 상태 설정 함수에 새 배열을 전달해야 해요. 기존 배열에서 filter()나 map() 같은 비변형(non-mutating) 메서드를 호출해 새 배열을 만들면 돼요.
| 작업 | 피하기 (배열 변형) | 선호 (새 배열 반환) |
|---|---|---|
| 추가 | push, unshift |
concat, [...arr] 스프레드 문법 |
| 제거 | pop, shift, splice |
filter, slice |
| 정렬 | reverse, sort |
먼저 복사본 만들기 |
배열에 항목 추가하기
배열 스프레드 문법으로 항목을 뒤에 붙이거나, 앞에 추가할 수도 있어요.
setArtists([
{ id: nextId++, name: name },
...artists // 기존 항목은 뒤로
]);
배열의 다른 변경
배열을 복사했다고 해서 그 안의 기존 항목을 직접 변형하면 안 돼요. 복사는 얕은(shallow) 복사라서, 복사한 배열의 항목 객체는 원본 배열과 같은 객체를 가리켜요. nextList[0].seen을 바꾸면 list[0].seen도 함께 바뀌는 상태 변형이 되어버려요.
배열 안의 객체 업데이트하기
객체는 진짜로 배열 "안에" 있는 게 아니에요. 배열 각 요소는 별개의 값이고, 배열이 그 값을 "가리킵니다." 그래서 list[0] 같은 중첩 필드를 바꿀 때는 조심해야 해요.
중첩 상태를 업데이트할 때는 바꾸려는 지점부터 최상위까지 복사본을 만들어야 해요.
map을 쓰면 변형 없이 기존 항목을 수정된 버전으로 교체할 수 있어요.
setMyList(myList.map(artwork => {
if (artwork.id === artworkId) {
// 변경 사항이 있는 *새* 객체 생성
return { ...artwork, seen: nextSeen };
} else {
// 변경 없음
return artwork;
}
}));
원칙 정리
일반적으로 방금 만든 객체만 변형할 수 있어요. 예를 들어 새 artwork를 삽입할 때는 그 객체 자체를 변형해도 되지만, 이미 상태에 있는 무언가를 다룰 때는 복사본을 만들어야 해요.
요약
- 배열을 상태에 넣을 수 있지만, 그 배열을 바꿀 수는 없어요.
- 배열을 변형하는 대신 새 버전을 만들어 상태를 그걸로 갱신해요.
[...arr, newItem]배열 스프레드 문법으로 새 항목이 포함된 배열을 만들 수 있어요.filter()와map()으로 필터링되거나 변형된 항목이 들어간 새 배열을 만들 수 있어요.
더 알아보기
- 상태의 객체 업데이트하기: https://react.dev/learn/updating-objects-in-state
- State: 스냅샷처럼: https://react.dev/learn/state-as-a-snapshot
- 컴포넌트 간 상태 공유: https://react.dev/learn/sharing-state-between-components