Describing the UI - Rendering Lists

hyocho·2023년 5월 26일
0

React

목록 보기
18/24
post-thumbnail

출처 : https://react.dev/learn/rendering-lists

데이터 집합에서 유사한 컴포넌트를 여러 개 표시하려고 하는 경우가 많다. 자바스크립트 배열 메소드를 사용하여 데이터 배열을 조작할 수 있다. 이 페이지에서는 filter()map() 을 리액트와 함께 사용하여 데이터 배열을 필터링하고 컴포넌트 배열로 변환한다.

배울 것

  • 자바스크립트의 map()을 사용하여 배열을 렌더링하는 방법
  • 자바스크립트의 filter()을 사용하여 특정한 컴포넌트만 렌더링하는 방법
  • 리액트의 key를 사용해야 하는 때와 그 이유

Rendering data from arrays

아래와 같은 리스트가 있다고 해보자.

<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()같은 방법을 사용하여 컴포넌트를 렌더링 할 수 있다.

다음은 배열에서 항목 목록을 생성하는 간단한 예이다.

  1. 배열로 데이터를 옮긴다.
const people = [
  'Creola Katherine Johnson: mathematician',
  'Mario José Molina-Pasquel Henríquez: chemist',
  'Mohammad Abdus Salam: physicist',
  'Percy Lavon Julian: chemist',
  'Subrahmanyan Chandrasekhar: astrophysicist'
];
  1. JSX 노드의 새 배열 listItemspeople의 구성원들을 Map한다.
const listItems = people.map(person => <li>{person}</li>);
  1. ul로 감싸져있는 listItems 를 반환한다.
return <ul>{listItems}</ul>;

Filtering arrays of items

이 데이터는 더 구조화될 수 있다.

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"(참 또는 거짓을 반환하는 함수)를 통과하고 테스트를 통과한 항목만 새 배열을 반환한다.(참으로 반환됨)

professionchemist인 항목만을 원한다. 이를 위한 "test"함수는 (person) => person.profession === 'chemist' 과 유사하다. 다음은 이를 통합하는 방법이다.

  1. person.profession === 'chemist'로 필터링된 peoplefilter()를 호출하여 'chemist' 인 사람들로 모인 chemist라는 배열을 만든다.
const chemists = people.filter(person =>
  person.profession === 'chemist'
);
  1. 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>
);
  1. 마지막으로 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 문을 작성해야 한다. 잊는다면 아무것도 반환되지 않을 것이다.

Keeping list items in order with 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를 생성한다기 보다, 데이터 안에 넣어야 한다.

DEEP DIVE

Displaying several DOM nodes for each list item

여러 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>의 리스트를 만들 것이다.

Where to get your key

데이터 소스에 따라 key 소스가 달라진다.

  • 데이터베이스로 부터의 데이터 : 데이터베이스로부터의 데이터라면 처음부터 고유한 데이터베이스의 key나 id를 사용하면 된다.
  • 로컬에서 생성된 데이터 : 데이터가 로컬에서 생성되고 지속되는 경우(예: 메모앱의 노트), 카운터 crypto.randomUUID() 또는 uuid 패키지를 사용한다.

Rules of keys

  • key는 고유해야 한다. 그러나 다른 배열에서는 같은 key를 사용해도 좋다.
  • key는 변하지 않아야 한다. 그렇지 않으면 목적을 잃을 것이다. 렌더링 도중에 생성하지 말 것.

Why does React need keys?

컴퓨터의 파일들에 이름이 없다고 가정해 보자. 대신 첫 번째, 두 번째 파일 등의 순서로 참조할 수 있다. 익숙해질 수 있지만 일단 파일을 삭제하면 혼란스러울 수 있다. 두 번째 파일이 첫 번째 파일이 되고 세 번째 파일이 두 번째 파일이 된다.

폴더의 파일 이름과 배열에서의 JSX key는 비슷한 목적을 가진다. 그것들은 우리가 그것의 형제들 사이의 항목을 고유하게 식별할 수 있게 해준다. 잘 선택된 key는 배열 내의 위치보다 더 많은 정보를 제공할 수 있다. 재배열때문에 위치가 변경되는 경우에도 key는 리액트가 생애주기동안 항목을 식별할 수 있게 해준다.

🕳️ Pitfall
배열에 있는 항목의 인덱스를 key로 사용하려고 할 수 있다. 실제로 key를 지정하지 않으면 리액트에서 이를 사용한다. 그러나 항목이 삽입되거나 삭제되거나 배열 순서가 변경되면 항목을 렌더링하는 순서가 시간이 지남에 따라 변경된다. key로서의 인덱스는 종종 미묘하고 혼란스러운 버그로 이어진다.
유사하게, key={Math.random()}와 같이 key를 즉석해서 만들지 말라. 이렇게 하면 렌더링 간에 key가 일치하지 않으므로 모든 컴포넌트와 DOM이 매번 다시 생성된다. 속도가 느릴 뿐만 아니라 목록 항목 내의 사용자 입력도 손실된다. 대신 데이터를 기반으로 한 안정적인 ID를 사용하라.
컴포넌트는 key를 props로 받지 못하는 것을 명심하라. 리액트 자체에서만 힌트로 사용된다. 컴포넌트에 ID가 필요한 경우 <Profile key={id} userId={id} /> 같이 별도의 props로 전달해야 한다.

Recap

  • 데이터를 컴포넌트에서 배열과 객체와 같은 데이터 구조로 이동하는 방법
  • 자바스크립트의 map()으로 유사한 컴포넌트의 집합을 생성하는 방법
  • 자바스크립트의 filter()으로 필터링된 항목의 배열을 만드는 방법
  • 위치나 데이터가 변경되더라도 리액트가 각 컴포넌트를 추적할 수 있도록 컬렉션의 각 컴포넌트에 대한 key를 설정하는 이유와 방법
profile
기록하는 습관을 기르고 있습니다.

0개의 댓글