1. 변이 없이 배열 업데이트하기
2. 배열 내부의 객체 업데이트하기
JavaScript에서 배열은 객체의 또 다른 종류일 뿐이다.
객체와 마찬가지로, React state의 배열은 읽기 전용으로 취급해야 한다.
즉, arr[0] = 'bird'
와 같이 배열 내부의 항목을 재할당해서는 안 되며, push()
및 pop()
과 같이 배열을 변이하는 메서드도 사용해서는 안된다.
대신 배열을 업데이트할 때마다 state 설정 함수에 새 배열을 전달하고 싶을 것이다.
그렇게 하려면 state의 원래 배열에서 filter()
및 map()
과 같은 비변이 메서드를 호출하여 새 배열을 만들면 된다.
그렇게 만들어진 새 배열을 state로 설정할 수 있다.
React state 내에서 배열을 다룰 때는 왼쪽 열의 메서드를 피하고 대신 오른쪽 열의 메서드를 선호해야 한다.
비추천 (배열 직접 변이) | 추천 (새 배열 반환) | |
---|---|---|
추가 | push, unshift | concat, [...arr] spread syntax (example) |
삭제 | pop, shift, splice | filter, slice (example) |
교체 | splice, arr[i] = ... assignment | map (example) |
정렬 | reverse, sort | 배열을 복사한 다음 처리(example) |
!주의!
- 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>
</>
);
}
setArtists([
{ id: nextId++, name: name },
...artists // Put old items at the end
]);
unshift()
의 기능을 모두 수행할 수 있다.1-2. 배열에서 제거하기
filter
메서드를 사용할 수 있다.setArtists(
artists.filter(a => a.id !== artist.id)
);
artists.filter(a => a.id !== artist.id)
구문은 artist.id
와 다른 ID를 가진 artists
로 구성된 배열을 생성한다”는 의미이다.1-3. 배열 변경하기
map()
을 사용하여 새로운 배열을 만들 수 있다.map
에 전달할 함수는 데이터 또는 인덱스(또는 둘 다)에 따라 각 항목에 대해 수행할 작업을 결정할 수 있다.1-4. 배열에서 항목 교체하기
ar[0] = 'bird'
와 같은 할당은 원래 배열을 변이하는 것이므로 이 경우에도 map
을 사용하는 것이 좋다.1-5. 배열에 삽입하기
...
배열 전개 구문과 slice()
메서드를 함께 사용할 수 있다.slice()
메서드를 사용하면 배열의 “조각”을 잘라낼 수 있다.slice
를 spread
한 다음 새 항목과 나머지 원래 배열을 펼치는 배열을 만든다.1-6. 배열에 다른 변경 사항 적용하기
전개 구문과 map()
및 filter()
와 같은 비변이 메서드만으로는 할 수 없는 일이 몇 가지 있다.
예를 들어, 배열을 반전시키거나 정렬하고 싶을 수 있다.
JavaScript reverse()
및 sort()
메서드는 원래 배열을 변이하므로 직접 사용할 수 없다.
대신, 배열을 먼저 복사한 다음 변이하면 된다.
배열을 복사하더라도 배열 내부의 기존 항목을 직접 변이할 수는 없다.
이는 얕은 복사가 이루어져 새 배열에는 원래 배열과 동일한 항목이 포함되기 때문이다.
따라서 복사된 배열 내부의 객체를 수정하면 기존 state를 변이하는 것이다.
예를 들어, 다음과 같은 코드가 문제가 됩니다.
const nextList = [...list];
nextList[0].seen = true; // Problem: mutates list[0]
setList(nextList);
nextList
와 list
는 서로 다른 배열이지만, nextList[0]
과 list[0]
은 같은 객체를 가리킨다.nextList[0].seen
을 변경하면 list[0].seen
도 변경하는 것이다.list[0]
과 같이 중첩된 필드를 변경할 때 주의해야 한다.2-1. Immer로 간결한 업데이트 로직 작성하기
[...arr, newItem]
을 사용하여 새 항목으로 배열을 만들 수 있다.filter()
및 map()
을 사용하여 필터링되거나 변형된 항목으로 새 배열을 만들 수 있다.https://developer.mozilla.org/ko/