다음과 같은 반복되는 markup을 보다 효율적으로 JSX로 나타낼 수 있을까?
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
</ul>
주목해야할 점은 기본적인 markup은 <li>
로 동일하나 그 안의 내용, 즉 데이터만 변한다는 사실이다. 따라서 React는, 이와 같이 반복되는 데이터의 경우, 이들을 JavaScript object나 array에 저장하고 map()
과 filter()
를 통해 순회하며 rendering하는 방식을 사용한다.
const contents = [
'list item 1',
'list item 2',
'list item 3',
'list item 4',
'list item 5',
];
export default function List() {
const listItems = contents.map(content =>
<li>{content}</li>
);
return <ul>{listItems}</ul>;
}
위의 예제에서는 map()
만을 사용했으나, 데이터들 중 특정 데이터들만 render해야할 경우 filter()
를 이용할 수 있다.
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
}, {
name: 'Percy Lavon Julian',
profession: 'chemist',
}, {
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
}];
위와 같은 데이터가 존재하며, 해당 데이터들 중 profession이 'chemist'
인 항목만 출력해야 한다고 하자. 이 경우 filter()
와 map()
을 함께 활용한다.
import { people } from './data.js';
export default function List() {
const chemists = people.filter(person =>
person.profession === 'chemist'
);
const listItems = chemists.map(person =>
// ...markup
);
return <ul>{listItems}</ul>;
}
key
위 예시들을 그대로 이용할 경우, console창에 다음과 같은 알림창이 발생한다.
⛔ Warning: Each child in a list should have a unique “key” prop.
해당 Warning
을 해결하기 위해선 아래와 같은 구현이 필요하다.
<li key={person.id}>...</li>
🚨 JSX elements directly inside a
map()
call always need keys!
명심하자. map()
을 통해 반복적으로 render되는 JSX는 반드시 key
를 전달해야 한다. Key들은 React에게 어떤 array item과 어떤 component가 대응되는지 알려주는 역할을 한다. 이는, array item이 수정으로 인해 변할 때, DOM을 올바르게 업데이트되도록 한다.
• Displaying several DOM nodes for each list item
map()
내에서 하나 이상의 DOM node를 render하며 동시에 하나의 JSX 태그로 묶여져 있지 않다면 <Fragment>
syntax를 이용한다.
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
이때, <>...</>
syntax를 사용할 경우 key를 전달할 수 없으니 주의하자.
• Where to get your key
어디서 key
를 가져올 수 있을까?
Data from a database : 가장 좋은 방법은 데이터 베이스 자체에 ID와 같은 unique한 속성을 보유하고 있는 것 이다.
Locally generated data : crypto.randomUUID()
나 uuid
와 같은 package를 이용하여 unique한 값을 생성하자.
• Rules of keys
Keys must be unique among siblings : 다시말해, 다른 array간에는 동일한 key를 가져도 상관없다.
Keys must not change : Do Not generate them while rendering!
• Why does React need keys?
앞서 말했듯, 불변하는 데이터에 대해서는 key의 의미가 크게 존재하지 않는다. 예를 들어, 당신이 이름없는 파일들을 관리한다고 생각하자. 최초에는 각 파일들을, 첫번째 파일, 두번째 파일, ...과 같이 순서로 구분할 수 있다. 그러나, 첫 파일이 삭제된 경우, 두번째 파일이 첫번째 파일로, 세번째 파일이 두번째 파일로, ... 변화하게 된다. 따라서, 계속해서 수정되는 파일의 집합의 경우 각 파일에 대한 이름, 즉, key가 필요하다.
🚨 Array item의 index를 key로 사용하는 것은 바람직하지 않다. 위에서 말한 것처럼 수정 시 각 index는 변하게 되므로 불변하는 값을 필요로 하는 key에는 적합하지 않다. 비슷하게
Math.random()
역시 바람직하지 않다. 매 render마다Math.random()
의 값이 변할 뿐만 아니라, unique함을 보장하지도 않는다.
🚨 Component는
key
를 prop으로 전달받지 않는다. 따라서 id 값이 필요한 경우<Profile key={id} userId={id} />
와 같이 독립적으로 전달받아야 한다.