📝 리스트와 Key
우선 JS에서 리스트를 변환하는 방법을 보겠습니다. 아래는 map()
함수를 이용해서 기존 배열의 값들을 2 곱하고 새로운 배열을 doubled
변수에 담는 예제입니다.
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
[2, 4, 6, 8, 10]
이 콘솔에 출력됩니다.
React에서 배열을 element의 리스트로 변환하는 것도 거의 비슷합니다.
다수 컴포넌트 렌더링
element 모음을 만들고 {}
를 사용해서 JSX안에 포함할 수 있습니다. 아래는 JS의 map()
함수를 이용해서 numbers
배열을 반복 실행합니다. 배열의 값 마다 <li>
element를 리턴합니다. 그리고 element 배열을 listItems
변수에 담습니다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);
listItems
배열을 <ul>
element 안으로 포함시키고 렌더링 하겠습니다.
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
이 코드는 1부터 5사이의 숫자 리스트를 보여줍니다.
기본 리스트 컴포넌트
흔히 컴포넌트 안에 element 리스트를 렌더링 합니다. 이전 예제를 컴포넌트로 바꾸는 작업을 하겠습니다.
이 코드를 실행하면 아래와 같은 경고 메세지를 콘솔에서 확인할 수 있습니다. 여기서 “key” 는 element 리스트를 만들 때 생성되는 특수한 문자 속성입니다.Warning: Each child in a list should have a unique “key” prop.
numbers.map()
안의 element에 key
를 넣어서 이 이슈를 해결합시다.
🔑 Keys
key
는 React가 각 아이템이 변화, 추가, 삭제할지 확인하는 것을 도와줍니다. key
는 element의 안정적인 고유성을 위해 배열 안의 element에게 줘야합니다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
key
를 정하는 방법 중 가장 좋은 것은 리스트의 다른 아이템 중에서 고유한 정체성을 가진 문자열을 사용하는 것입니다. 흔한 방법은 데이터의 ID
를 사용하는 것 입니다.
const todoItems = todos.map((todo) =>
<li keys={todo.id}>
{todo.text}
</li>
);
렌더링 된 아이템이 안정적인 ID
가 없을 때 최후의 수단으로 아이템의 인덱스를 key
로 사용할 수 있습니다.
const todoItems = todos.map((todo, index) =>
<li key={index}>
{todo.text}
</li>
);
아이템의 순서가 바뀐다면 key
를 인덱스로 지정하는 방식을 추천하지 않습니다. 성능에 안좋은 영향을 줄 수 있고 컴포넌트의 state 이슈를 불러올 수 있습니다. Robin Pokorny 의 관련 글을 확인해주세요.
Key로 컴포넌트 추출
key
는 주변 배열의 context에서만 의미가 있습니다. 예로 만약 ListItem
컴포넌트를 추출한다면 <li>
element 대신 <ListItem />
element에서 key
를 유지해야합니다.
경험 상 map()
안의 element에게 key
를 주는 것이 좋습니다.
Key는 형제 사이에서만 고유한 값이어야 합니다.
key
는 배열 안에서 고유한 값이어야 하고 전체에서는 고유하지 않아도 됩니다. 다른 배열에서 같은 값의 key
를 사용해도 됩니다.
key
는 React에게 힌트를 제공하지만 컴포넌트로 전달하지 않습니다. 컴포넌트에서 같은 값이 필요하다면 다른 이름의 props로 전달하면 됩니다.
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title}
/>
);
위 예제에서 Post
컴포넌트는 props.id
를 읽을 수 있지만 props.key
는 읽지 못합니다.
JSX에서 map( ) 함수 포함하기
위 예제에서 별도의 listItems
변수를 선언하고 이를 JSX에 포함했습니다.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
);
return <ul>{listItems}</ul>;
}
JSX에서 {}
를 쓰면 표현식을 쓸 수 있습니다. map()
을 인라인으로 써보겠습니다.
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{
numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
)
}
</ul>
);
}
때론 이 코드가 더 깔끔할 수 있습니다. 하지만 이 방식을 자주 사용하는 것은 좋지 않습니다. JS와 마찬가지로 가독성을 위해 변수로 추출 할지를 고민 해야 합니다. map()
이 중첩되면 컴포넌트를 추출하는 것이 좋을 수 있습니다.
📚 정리 및 참고 자료
- element를 리스트로 정의 할 때는
key
라는 속성을 지정해야 합니다. - 같은 배열 안의 element는 고유한
key
값을 가져야 합니다. key
는 주변 배열의 context에서만 의미가 있습니다.