const data = [
{
id: 1,
username: 'user1',
email: 'user1@gmail.com'
},
{
id: 2,
username: 'user2',
email: 'user2@gmail.com'
},
{
id: 3,
username: 'user3',
email: 'user3@gmail.com'
},
...
]
위와 같은 배열 형식의 데이터를 서버로부터 받아왔고, 각 요소를 렌더링해야 한다고 해보자.
만약 데이터의 양이 엄청나게 많다면, 하나하나를 렌더링하는 코드를 짜려면 엄청난 양의 코드를 작성해야한다.
하지만 데이터들이 동일한 구조를 가진다는 것을 이용해, map 메서드를 사용하면 하나의 요소만 구현하는 코드만으로 전체를 구현하는 코드를 작성하는 것이 가능하다.
또, filter 메서드나 sort 메서드를 이용하면 요소들을 편집하거나 정렬하는 것이 가능하다.
const UserList = () => {
const [data, setData] = useState(initialData);
return (
<ul>
{data.map(user => (
<li key={user.id}>
<div>ID: {user.id}</div>
<div>Username: {user.username}</div>
<div>Email: {user.email}</div>
</li>
))}
</ul>
);
};
map 메서드는 'data' 의 각 요소를 순회하면서, 콜백함수의 리턴값에 해당하는 요소를 반환한다.
map 메서드가 data 를 순회하면서 각 요소에 따른 li 태그를 반환하기 때문에, UserList 컴포넌트는 결국 전체 data 요소를 담은 리스트를 반환한다.
const UserList = () => {
const [data, setData] = useState(initialData);
const handleDelete = (id) => {
// Button 을 누른 데이터의 id 에 해당하는 요소를 제외한 새로운 배열 생성
const newData = data.filter(item => item.id !== id);
// 새로운 배열을 기존의 data 에 덮어 씌운다.
setData(newData);
};
return (
<div>
<h2>User List</h2>
<ul>
{data.map(user => (
<li key={user.id}>
<div>ID: {user.id}</div>
<div>Username: {user.username}</div>
<div>Email: {user.email}</div>
// 삭제를 실행하기 위한 button 태그
<button onClick={() => handleDelete(user.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
};
filter 메서드는 data 를 순회하며, 조건(콜백함수의 리턴값) 에 맞는 요소들만을 추출한 배열을 반환한다.
Delete button 의 onClick 이벤트 핸들러로 바인딩된 'handleDelete' 함수는 해당 버튼을 가진 요소의 key(id) 값을 인수로 받는다.
버튼이 눌리면 함수 내에서 filter 메서드를 통해 '해당 key 값에 해당하지 않는 요소들' 만을 추출한 배열을 data state 에 저장하고, UserList 컴포넌트가 재렌더링이 이루어지면서 바뀐 data 에 해당하는 리스트가 다시 렌더링된다.
결과적으로는 해당 버튼을 가진 요소의 데이터만을 삭제한 배열이 렌더링된다.
filter 의 조건을 컨트롤하여 이와 같이 요소를 삭제하거나, 요소를 추가하는 '편집' 이 가능하다.
const UserList = () => {
const [data, setData] = useState(initialData);
const handleSort = () => {
//
const sortedData = data.sort((a, b) => b.id - a.id);
setData(sortedData);
};
return (
<div>
<h2>User List</h2>
// 정렬을 실행하기 위한 button 태그
<button onClick={handleSort}>Sort Descending</button>
<ul>
{data.map(user => (
<li key={user.id}>
<div>ID: {user.id}</div>
<div>Username: {user.username}</div>
<div>Email: {user.email}</div>
</li>
))}
</ul>
</div>
);
};
sort 메서드는 data 를 순회하며, 두 개의 요소를 조건에 따라 비교하며 정렬을 진행하고, 정렬된 배열을 반환한다.
위의 경우, (콜백함수의 리턴값이 0 또는 음수인 경우 a, b / 리턴값이 양수인 경우 b, a) 로 정렬이 이루어진다.
Sort Descending button 을 누르면 핸들러로 바인딩된 handleSort 함수 내의 sort 메서드는 기존 data 를 역순으로 정렬한 배열을 반환한다.
setData 를 통해 정렬된 배열이 data state 에 저장되면, UserList 컴포넌트가 리렌더링 되면서 바뀐 data 에 해당하는 배열이 렌더링된다.
// 각 요소마다 유니크한 key prop 을 지정해주어야 한다.
<li key={user.id}>
<div>ID: {user.id}</div>
<div>Username: {user.username}</div>
<div>Email: {user.email}</div>
</li>
배열 렌더링을 진행할 때는 반드시 각 요소마다 고유한 값을 가지는 key prop 를 설정해주는 것이 좋다.
그 이유는 React 가 각 요소를 정확하게 인식하고 작업을 처리하기 수월하기 때문이다.
만약 [사과, 포도, 망고] 인 배열에서 '포도' 가 삭제되었다고 생각해보자.
그럼 과정 없이 결과만을 본다면, '포도' 가 삭제된건지, '망고' 가 삭제되고 '포도' 가 '망고' 로 변경된 것인지를 구분하기가 쉽지 않다.
하지만 key prop 이 존재한다면, 각 요소를 파악하고 추적하는 것이 가능하기 때문에 위와 같은 경우를 구별할 수 있다.
이를 통해 변화된 요소를 추적해 그 요소만을 렌더링하거나, 원하는 대로 배열을 편집 및 수정하는 등 효율적인 리스트 관리가 가능하다. 또, key 값은 고유하므로 중복된 key 값이 생기는 등의 예기치않은 동작을 방지할 수 있다.