리스트 렌더링
데이터 집합에서 여러 개의 유사한 컴포넌트들을 표시하려는 경우가 많습니다. JavaScript 배열 메서드를 사용하여 데이터 배열을 조작할 수 있습니다. 이 페이지에서는 filter()
와 map()
을 React와 사용해 데이터 배열을 컴포넌트 배열로 필터링하고 변환해보겠습니다.
You will learn
- JavaScript의
map()
을 사용하여 배열을 컴포넌트로 렌더링하는 방법 - JavaScript의
filter()
를 사용하여 특정 컴포넌트만 렌더링하는 방법 - React에서 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>
리스트 항목들 사이의 유일한 차이점은 내용과 데이터입니다. 댓글 목록에서 프로필 이미지 갤러리에 이르기까지 인터페이스를 구성할 때 서로 다른 데이터를 사용하여 동일한 컴포넌트의 여러 인스턴스를 표시해야 하는 경우가 많습니다. 이러한 상황에서 해당 데이터를 JavaScript의 객체와 배열에 저장할 수 있으며 그것들의 컴포넌트 리스트를 렌더링하기 위해 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'
];
people
의 요소들을 새로운 JSX 노드의 배열인listItems
로 매핑하기
const listItems = people.map(person => <li>{person}</li>);
- 컴포넌트에서
listItems
를<ul>
로 래핑해서 반환하기
return <ul>{listItems}</ul>;
결과는 다음과 같습니다.
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); 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',
}];
직업이 ’chemist’
인 사람들만 보여주고 싶다고 생각해봅시다. 해당하는 사람들만 반환하기 위해 JavaScript의 filter()
메서드를 사용할 수 있습니다. 이 메서드는 배열을 가져와서 “test” (true
나 false
를 반환하는 함수)로 항목을 넘겨주고 test에 통과된 항목(true
가 반환된 항목)만 있는 새로운 배열을 반환합니다.
직업
이 ’chemist’
인 항목만 필요합니다. 이를 위한 “test” 함수는 (person) => person.profession === 'chemist'
와 같을 것입니다. 이것을 적용하는 과정은 다음과 같습니다.
people
에서filter()
를 호출해person.profession === 'chemist'
로 필터링해서 “chemist”인 사람만 있는 새로운 배열chemists
를 생성합니다.
const chemists = people.filter(person =>
person.profession === 'chemist'
);
- 이제
chemists
를 매핑합니다.
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>;
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemist' ); 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> ); return <ul>{listItems}</ul>; }
key
를 사용해서 리스트 항목을 순서대로 유지하기
위의 샌드박스 중 하나를 새 탭에서 열면 콘솔에서 다음과 같은 에러를 볼 수 있습니다.
배열의 다른 항목 간에 고유하게 식별되는 문자열이나 숫자 형태의 key
를 각 배열 항목에 주어야 합니다.
<li key={person.id}>...</li>
Key는 각 컴포넌트가 어떤 배열 항목에 해당하는지 알려주어 React가 나중에 그것들을 일치시킬 수 있도록 해줍니다. 이것은 예를 들어 정렬로 인해 배열 항목이 이동, 삽입 또는 삭제되는 경우 중요한 문제가 됩니다. 잘 선택된 key
는 React가 정확히 무슨 일이 일어났는지 유추해서 DOM 트리에 적절하게 반영할 수 있도록 도와줍니다.
즉석에서 key를 생성하는 대신 데이터 안에 key를 포함해야 합니다.
export const people = [{ id: 0, // JSX에서 key로 사용됩니다. name: 'Creola Katherine Johnson', profession: 'mathematician', accomplishment: 'spaceflight calculations', imageId: 'MK3eW3A' }, { id: 1, // JSX에서 key로 사용됩니다. name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', accomplishment: 'discovery of Arctic ozone hole', imageId: 'mynHUSa' }, { id: 2, // JSX에서 key로 사용됩니다. name: 'Mohammad Abdus Salam', profession: 'physicist', accomplishment: 'electromagnetism theory', imageId: 'bE7W1ji' }, { id: 3, // JSX에서 key로 사용됩니다. name: 'Percy Lavon Julian', profession: 'chemist', accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', imageId: 'IOjWm71' }, { id: 4, // JSX에서 key로 사용됩니다. name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', accomplishment: 'white dwarf star mass calculations', imageId: 'lrWQx8l' }];
Deep Dive
각 항목이 하나가 아닌 여러 개의 DOM 노드들에 렌더링해야 하는 경우에는 어떻게 해야 할까요?
짧은 <> </>
fragment 문법은 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>
);
Fragments는 DOM에서 사라지므로 <h1>
, <p>
, <h1>
, <p>
등의 평평한 리스트가 생성됩니다.
key
를 어디에서 가져올까요?
다양한 데이터 소스가 다양한 key 소스를 제공합니다
- 데이터베이스의 데이터: : 데이터베이스에서 데이터를 가져오는 경우 본질적으로 고유한 데이터베이스의 key 및 ID를 사용할 수 있습니다.
- 로컬에서 생성된 데이터: 노트작성 앱의 노트처럼 데이터가 로컬에서 생성되고 유지되는 경우에는 항목을 생성할 때 증가하는 일련번호나
crypto.randomUUID()
또는uuid
같은 패키지를 사용해야 합니다.
key 규칙
- key는 형제간에 유일해야 합니다. 하지만 같은 key를 다른 배열에 있는 JSX 노드가 사용하는 것은 괜찮습니다.
- key는 바뀔 수 없으며 그렇게 되면 key는 목적을 잃게 됩니다. 렌더링 중에는 key를 생성하지 마십시오.
React에 key가 왜 필요할까요?
데스크탑에 있는 파일에 이름이 없다고 상상해 봅시다. 대신 첫 번째 파일, 두 번째 파일 등의 순서로 그것들을 참조하는 겁니다. 익숙해질 수도 있지만, 파일을 삭제한다면 혼란스러워질 것입니다. 두 번째 파일은 첫 번째 파일이 될 것이고 세 번째 파일은 두 번째 파일이 되는 식입니다.
폴더에 있는 파일명과 배열의 JSX key는 비슷한 용도로 사용됩니다. 이를 통해 형제간 항목들을 고유하게 식별할 수 있습니다. 잘 선택된 key는 배열 내 위치보다 더 많은 정보를 제공합니다. 재 정렬로 _위치_가 변경되어도 key
는 React가 항목의 생명주기 동안 해당 항목을 식별할 수 있게 해줍니다.
Recap
이 페이지에서 학습한 내용
- 컴포넌트에서 배열 및 객체와 같은 데이터 구조로 데이터를 이동하는 방법
- JavaScript의
map()
을 사용하여 유사한 컴포넌트 집합을 생성하는 방법 - JavaScript의
filter()
를 사용하여 필터링 된 항목의 배열을 생성하는 방법 - 컬렉션에서 각 컴포넌트에
key
를 설정하여 위치나 데이터가 변경되더라도 React가 각 컴포넌트를 추적할 수 있도록 하는 이유 및 방법
Challenge 1 of 4: 리스트를 둘로 나누기
예시는 모든 사람의 리스트를 보여줍니다.
두 개의 개별 리스트 Chemists와 Everyone Else을 차례로 표시하도록 변경하세요. 이전과 마찬가지로 person.profession === 'chemist'
를 확인하여 누가 chemist인지 여부를 확인할 수 있습니다.
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); }