데이터 집합에서 유사한 컴포넌트를 여러 개 표시하려고 하는 경우가 많다. 자바스크립트 배열 메소드를 사용하여 데이터 배열을 조작할 수 있다. 이 페이지에서는 filter()
와 map()
을 리액트와 함께 사용하여 데이터 배열을 필터링하고 컴포넌트 배열로 변환한다.
배울 것
- 자바스크립트의
map()
을 사용하여 배열을 렌더링하는 방법- 자바스크립트의
filter()
을 사용하여 특정한 컴포넌트만 렌더링하는 방법- 리액트의 key를 사용해야 하는 때와 그 이유
아래와 같은 리스트가 있다고 해보자.
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
리스트 항목들 사이의 유일한 차이점은 내용과 데이터이다. 인터페이스를 작성할 때 주석 목록에서 프로필 이미지 갤러리에 이르기까지 다른 데이터를 사용하여 동일한 컴포넌트의 여러 인스턴스를 표시해야 하는 경우가 많다. 이 상황에서 자바스크립트 객체 및 배열에 저장하고 map()
, filter()
같은 방법을 사용하여 컴포넌트를 렌더링 할 수 있다.
다음은 배열에서 항목 목록을 생성하는 간단한 예이다.
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
listItems
에 people
의 구성원들을 Map
한다.const listItems = people.map(person => <li>{person}</li>);
ul
로 감싸져있는 listItems
를 반환한다.return <ul>{listItems}</ul>;
이 데이터는 더 구조화될 수 있다.
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()
메소드를 사용하여 이 사람들을 반환해줄 수 있다. 이 메소드는 항목들의 배열을 받아 "test"(참 또는 거짓을 반환하는 함수)를 통과하고 테스트를 통과한 항목만 새 배열을 반환한다.(참으로 반환됨)
profession
이 chemist
인 항목만을 원한다. 이를 위한 "test"함수는 (person) => person.profession === 'chemist'
과 유사하다. 다음은 이를 통합하는 방법이다.
person.profession === 'chemist'
로 필터링된 people
에 filter()
를 호출하여 'chemist' 인 사람들로 모인 chemist
라는 배열을 만든다. const chemists = people.filter(person =>
person.profession === 'chemist'
);
chemist
에 map 한다.const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
known for {person.accomplishment}
</p>
</li>
);
listItems
를 반환한다.return <ul>{listItems}</ul>;
화살표 함수는
=>
직후에 암묵적으로 식을 반환하므로return
문이 필요하지 않다.const listItems = chemists.map(person => <li>...</li> // Implicit return! );
하지만
=>
뒤에 중괄호가 오면 반드시return
을 명시적으로 사용해야한다.const listItems = chemists.map(person => { // Curly brace return <li>...</li>; });
=> {
을 포함하는 화살표 함수를 '블록 바디'라고 한다. 그것은 한 줄 정도를 더 쓰도록 하겠지만 직접 return 문을 작성해야 한다. 잊는다면 아무것도 반환되지 않을 것이다.
key
//console.log
Warning: Each child in a list should have a unique “key” prop.
배열의 각 항목에 고유하게 식별하는 문자열이나 숫자로 key
값을 부여해야 한다.
<li key={person.id}>...</li>
map()
호출에 직접 포함된 JSX요소는 언제나 key가 필요하다!
key는 각 컴포넌트가 나중에 일치할 수 있도록 각 컴포넌트가 대응하는 배열 항목을 알려준다. 배열의 항목이 이동하거나(정렬으로 인해) 삽입되거나 삭제될 경우 이 작업이 중요하다. 잘 선택된 키는 리액트가 정확히 무슨 일이 일어났는지 추론하고 DOM트리를 정확하게 업데이트 하는 데 도움이 된다.
key를 생성한다기 보다, 데이터 안에 넣어야 한다.
여러 DOM노드를 렌더링해야 할 경우 어떻게 해야하는가?
<>...</> Fragment문법 에는 key를 넘길 수 없으므로 key를 하나의 <div>
로 그룹화하거나 약간 더 길고 명시적인 Fragment 문법을 사용해야 한다.
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
Fragment들은 DOM으로부터 사라져서 <h1>
,<p>
,<h1>
,<p>
의 리스트를 만들 것이다.
key
데이터 소스에 따라 key 소스가 달라진다.
컴퓨터의 파일들에 이름이 없다고 가정해 보자. 대신 첫 번째, 두 번째 파일 등의 순서로 참조할 수 있다. 익숙해질 수 있지만 일단 파일을 삭제하면 혼란스러울 수 있다. 두 번째 파일이 첫 번째 파일이 되고 세 번째 파일이 두 번째 파일이 된다.
폴더의 파일 이름과 배열에서의 JSX key는 비슷한 목적을 가진다. 그것들은 우리가 그것의 형제들 사이의 항목을 고유하게 식별할 수 있게 해준다. 잘 선택된 key는 배열 내의 위치보다 더 많은 정보를 제공할 수 있다. 재배열때문에 위치가 변경되는 경우에도 key는 리액트가 생애주기동안 항목을 식별할 수 있게 해준다.
🕳️ Pitfall
배열에 있는 항목의 인덱스를 key로 사용하려고 할 수 있다. 실제로 key를 지정하지 않으면 리액트에서 이를 사용한다. 그러나 항목이 삽입되거나 삭제되거나 배열 순서가 변경되면 항목을 렌더링하는 순서가 시간이 지남에 따라 변경된다. key로서의 인덱스는 종종 미묘하고 혼란스러운 버그로 이어진다.
유사하게,key={Math.random()}
와 같이 key를 즉석해서 만들지 말라. 이렇게 하면 렌더링 간에 key가 일치하지 않으므로 모든 컴포넌트와 DOM이 매번 다시 생성된다. 속도가 느릴 뿐만 아니라 목록 항목 내의 사용자 입력도 손실된다. 대신 데이터를 기반으로 한 안정적인 ID를 사용하라.
컴포넌트는 key를 props로 받지 못하는 것을 명심하라. 리액트 자체에서만 힌트로 사용된다. 컴포넌트에 ID가 필요한 경우<Profile key={id} userId={id} />
같이 별도의 props로 전달해야 한다.
map()
으로 유사한 컴포넌트의 집합을 생성하는 방법filter()
으로 필터링된 항목의 배열을 만드는 방법key
를 설정하는 이유와 방법