
데이터 모음에서 유사한 여러 컴포넌트를 나열하고 싶은 경우가 많다. JavaScript array methods를 사용하여 데이터 배열을 조작할 수 있다. 이 페이지에서는 리액트와 함께 filter() 과map() 을 사용하여 데이터 배열을 필터링하고 컴포넌트 배열로 변환한다.

컨텐츠 목록이 있다고 가정한다.
<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()와 같은 메서드를 사용하여 컴포넌트 목록을 렌더링할 수 있다.
다음은 배열에서 항목 목록을 생성하는 방법에 대한 간단한 예이다.
Move the data into an array:
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
Map the people members into a new array of JSX nodes, listItems:
const listItems = people.map(person => <li>{person}</li>);
Return listItems from your component wrapped in a <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 를 반환하는 함수)를 통해 전달하고 테스트를 통과한(true반환) 항목만 표함된 새 배열을 반환한다.
profession 가'chemist' 인 항목만 원한다. 이에 대한 “test”함수는 (person) => person.profession === 'chemist' 와 같다. 조합하는 방법은 다음과 같다
Create a new array of just “chemist” people, chemists, by calling filter() on the people filtering by person.profession === 'chemist':
const chemists = people.filter(person =>
person.profession === 'chemist'
);
Now map over 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>
);
Lastly, return the listItems from your component:
return <ul>{listItems}</ul>;
// App.js
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>;
}
// data.js
export const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
accomplishment: 'spaceflight calculations',
imageId: 'MK3eW3A'
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
accomplishment: 'discovery of Arctic ozone hole',
imageId: 'mynHUSa'
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
accomplishment: 'electromagnetism theory',
imageId: 'bE7W1ji'
}, {
id: 3,
name: 'Percy Lavon Julian',
profession: 'chemist',
accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
imageId: 'IOjWm71'
}, {
id: 4,
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
accomplishment: 'white dwarf star mass calculations',
imageId: 'lrWQx8l'
}];
// utils.js
export function getImageUrl(person) {
return (
'https://i.imgur.com/' +
person.imageId +
's.jpg'
);
}
💡 Pitfall
화살표 함수는 => 바로 다음에 암묵적으로 식을 반환하므로 return 문이 필요하지 않는다
const listItems = chemists.map(person =>
<li>...</li> // Implicit return!
);
하지만 => 다음에 { 중괄호가 있으면 return 를 적어줘야한다.
const listItems = chemists.map(person => { // Curly brace
return <li>...</li>;
})
=> { 를 포함하는 화살표 함수는 “block body”을 갖는다고 한다. 한 줄 이상의 코드를 작성할 수 잇찌만 return 는 직접 작성해야한다. 잊어버리면 아무것도 반환되지 않는다.
key위의 모든 샌드박스는 콘솔에 오류를 표시한다.
Warning: Each child in a list should have a unique “key” prop.
각 배열 항목에 key(해당 배열의 다른 항목 중에서 고유하게 식별하는 문자열 또는 숫자)를 제공해야 한다.
<li key={person.id}>...</li>
💡 Note
map() 호출 바로 내부의 JSX 요소에는 항상 키가 필요하다.
키는 리액트에게 각 컴포넌트가 해당하는 배열 항목을 알려주므로 나중에 매치시킬 수 있다. 배열 항목이 이동(예 : 정렬로 인해), 삽입 또는 삭제될 수 있는 경우 이는 중요해진다. 잘 선택된 key 는 리액트가 정확히 무슨 일이 일어났는지 추론하고 DOM 트리를 올바르게 업데이트 하는 데 도움이 된다.
즉석에서 키를 생성하는 대신 데이터에 키를 포함해야 한다.
// App.js
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 <ul>{listItems}</ul>;
}
// data.js
export const people = [{
id: 0, // Used in JSX as a key
name: 'Creola Katherine Johnson',
profession: 'mathematician',
accomplishment: 'spaceflight calculations',
imageId: 'MK3eW3A'
}, {
id: 1, // Used in JSX as a key
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
accomplishment: 'discovery of Arctic ozone hole',
imageId: 'mynHUSa'
}, {
id: 2, // Used in JSX as a key
name: 'Mohammad Abdus Salam',
profession: 'physicist',
accomplishment: 'electromagnetism theory',
imageId: 'bE7W1ji'
}, {
id: 3, // Used in JSX as a key
name: 'Percy Lavon Julian',
profession: 'chemist',
accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
imageId: 'IOjWm71'
}, {
id: 4, // Used in JSX as a key
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
accomplishment: 'white dwarf star mass calculations',
imageId: 'lrWQx8l'
}];
// utils.js
export function getImageUrl(person) {
return (
'https://i.imgur.com/' +
person.imageId +
's.jpg'
);
}
💡 DEEP DIVE
각 목록 항목에 대해 여러 DOM 노드 표시
각 항목이 하나가 아닌 여러 DOM 노드를 렌더링해야 하는 경우 어떻게 해야하나?
짧은 [<>...</> Fragment](https://react.dev/reference/react/Fragment) 구문으로는 키를 전달할 수 없으므로 키를 단일 <div> 로 그룹화하거나 약간 더 길고 더 명확한 more explicit <Fragment> 구문을 사용해야 한다.
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
DOM에서 Fragments는 사라지므로 <h1>, <p>, <h1>, <p> 등의 플랫 목록이 생성된다.
key서로 다른 데이터 소스는 서로 다른 키 소스를 제공한다.
데스크톱의 파일에 이름이 없다고 상상해 보아라. 대신 첫 번째 파일, 두 번째 파일 등의 순서로 참조할때, 익숙해질 수 있지만 일단 파일을 삭제하면 혼란스러워질 것이다. 두 번째 파일은 첫 번째 파일이 되고 세 번째 파일은 두 번째 파일이 되는 식이다.
폴더의 파일 이름과 배열의 JSX 키는 비슷한 용도로 사용된다. 이를 통해 형제 간에 항목을 고유하게 식별할 수 있다. 잘 선택된 키는 배열 내의 위치보다 더 많은 정보를 제공한다. 재정렬로 인해 위치가 변경되더라도 key 를 통해 리액트는 전체 생명 주기 동안 항목을 식별할 수 있다.
배열에서 항목의 인덱스를 키로 사용하고 싶은 유혹을 느낄 수 있다. 실제로 key를 전혀 지정하지 않으면 리액트가 인덱스를 사용하는 것이다. 하지만 항목을 삽입하거나 삭제하거나 배열이 재정렬되는 경우 항목을 렌더링하는 순서는 시간이 지남에 따라 변경된다. 인덱스를 키로 사용하면 종종 미묘하고 혼란스러운 버그가 발생한다.
마찬가지로 key={Math.random()} 으로 즉석에서 키를 생성하면 안된다. 이로 인해 렌더링 간에 키가 일치하지 않아 컴포넌트와 DOM이 매번 다시 생성된다. 이것은 느릴 뿐만 아니라 배열 항목 내부의 사용자 입력도 잃게 된다. 대신 데이터를 기반으로 안정적인 ID를 사용해라.
컴포넌트는 key 를 props로 받지 않는다. 리액트 자체에서 힌트로만 사용된다. 컴포넌트에 ID가 필요한 경우 <Profile key={id} userId={id} /> 와 같이 별도의 props로 전달해야 한다.
map() 으로 유사한 컴포넌트 셋을 생성하는 방법filter() 로 필터링된 항목의 배열을 만드는 방법key 를 설정하는 이유와 방법