리스트
import React from "react";
const IterationSample = () => {
return (
<ul>
<li>봄</li>
<li>여름</li>
<li>가을</li>
<li>겨울</li>
</ul>
);
};
export default IterationSample;
위의 코드를 보면 <li></li>가 반복되는 것을 알 수 있다. 지금은 ul태그 하나 뿐이라 그렇게 문제가 되지는 않아 보인다. 그렇지만 코드가 좀 더 복잡하다면 코드의 양은 더욱 늘어날 것이고, 파일 용량도 쓸데없이 증가할 것다. 코드 관리가 점점 어려워질 것이다.
→ 이러한 경우는 map()을 사용하여 반복적인 코드를 정리해서 정리하면 된다.
import React from "react";
const IterationSample = () => {
const names = ["눈사람", "얼음", "눈", "바람"];
const nameList = names.map((name) => <li>{name}</li>);
return <ul>{nameList}</ul>;
};
export default IterationSample;
이렇게 작성하다보면 웹에는 key를 쓰라는 경고가 뜬다.
key
개념
key는 리스트를 만들때 포함해야하는 속성값이며, 리스트를 렌더링 할때 어떤것에 변경이 있었는지 알아내려고 사용합니다.
공식문서에 따르면 Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕습니다. key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 합니다.
필요성
key가 없을 때는 virtual dom이 비교하는 과정에서 리스트를 순차적으로 비교하면서 감지합니다. 하지만 key가 있으면 어떤 변화가 일어났는지 빠르게 알아낼수 있습니다.
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
리액트는 이전 리스트와 현재 리스트를 순회하고 차이점을 발견하면 변경한다. 이 예시에서는 맨끝에 li태그를 추가를 했다. 그래서 1번째 2번째 li태그가 같아서 넘어가고, li태그를 3번째에 추가한다.
그러나 이 아래 예시를 살펴보면,
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
이런식으로 맨앞에 리스트가 추가가 되면, 모두 다르다고 판단하여 모든 요소를 변경한다. 이러한 문제를 해결하기 위해 key가 만들어 졌다.
<ul>
<li key="2015">Hello</li>
<li key="2016">Rect</li>
</ul>
<ul>
<li key="2014">Bye</li>
<li key="2015">Hello</li>
<li key="2016">Rect</li>
</ul>
이렇게 key를 가지고 있어서 앞에 요소가 추가가 되더라도, 2015,2016 키를 가진 데이터는 이동만 하면되고, 2014키를 가진 데이터만 추가가 되게 된다.
주의점
Key를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것입니다. 대부분의 경우 데이터의 ID를 key로 사용합니다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
Key를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용한다. 대부분의 경우 데이터의 ID를 key로 사용한다.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
렌더링 한 항목에 대한 안정적인 ID가 없다면 최후의 수단으로 항목의 인덱스를 key로 사용할 수 있다.
또한, 항목의 순서가 바뀔 수 있는 경우 key에 인덱스를 사용하는 것은 권장하지 않는다. 이로 인해 성능이 저하되거나 컴포넌트의 state와 관련된 문제가 발생할 수 있다.
Key로 컴포넌트 추출
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 맞습니다! 배열 안에 key를 지정해야 합니다.
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
예를 들어 ListItem컴포넌트를 추출한 경우 ListItem안에 있는 <li>엘리먼트가 아니라 배열의 <ListItem />엘리먼트가 key를 가져야 한다.
jsx에 map표시
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
두가지 방식으로 표현할 수 있겠지만, jsx에 map()의 함수의 결과를 인라인으로 처리할 수 있다.