React/공식 문서

Props와 리스트 렌더링

favor 2026. 3. 25. 03:19

컴포넌트에 props 전달하기

부모 컴포넌트는 props를 줌으로써 자식 컴포넌트에게 정보를 전달 가능

 

✔️ 친숙한 props

props : JSX 태그에 전달하는 정보

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return (
    <Avatar />
  );
}

^ className, src, alt, width, height와 같은 속성은 <img> 태그에 전달 가능

 

✔️ 컴포넌트에 props 전달하기

export default function Profile() {
  return (
    <Avatar />
  );
}

^ 어떠한 props도 전달하지 않는 상태

 

1단계 : 자식 컴포넌트에 props 전달하기

export default function Profile() {
  return (
    <Avatar
      person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
      size={100}
    />
  );
}

^ person (객체)과 size (숫자)를 전달

 

2단계 : 자식 컴포넌트 내부에서 props 읽기

function Avatar({ person, size }) {
  // person과 size는 이곳에서 사용가능합니다.
}

 

✔️ prop의 기본값 지정하기

값이 지정되지 않았을 때, prop에 기본값을 주길 원한다면, 변수 바로 뒤에 기본값을 넣어줌

function Avatar({ person, size = 100 }) {
  // ...
}

> size prop이 없이 렌더링 된다면, size는 100으로 설정됨

 

✔️ JSX spread 문법으로 props 전달하기

function Profile({ person, size, isSepia, thickBorder }) {
  return (
    <div className="card">
      <Avatar
        person={person}
        size={size}
        isSepia={isSepia}
        thickBorder={thickBorder}
      />
    </div>
  );
}

^ Profile이 4개의 데이터를 받아서 Avatar에게 일일이 하나씩 전달하는 코드

--> 가독성은 높지만, 데이터의 양이 많아지면 코드가 길어짐

 

function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

^ spread 문법을 통해 Profile이 받는 모든 props를 Avatar에게로 전달하는 코드

--> 코드가 깔끔해짐

 

* spread 문법은 편하지만, 남용하는 것은 좋지 않음

위의 예시처럼 Profile이 단순히 Avatar의 wrapper 역할을 할 때에만 사용하는 것이 좋음

= 받은 데이터 그대로 전달할 때에만

 

✔️ 자식을 JSX로 전달하기

<Card>
  <Avatar />
</Card>

^ Card : 부모 / Avatar : 자식

부모 태그 사이의 있는 콘텐츠는 children이라는 이름으로 부모 컴포넌트에게 전달됨

 

import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children} {/* ← 이 자리가 바로 Avatar가 나타날 곳 */}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Profile() 내부에서 Card 컴포넌트 아래에 Avatar 컴포넌트가 존재 --> Card : 부모, Avatar : 자식 즉, children

 

 

 


조건부 렌더링

React는 if문, && 및 ? : 연산자와 같은 자바스크립트 문법을 사용하여 조건부로 JSX를 렌더링할 수 있음

 

✔️ 조건부로 JSX 반환하기

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name} ✅</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item
          isPacked={true}
          name="Space suit"
        />
        <Item
          isPacked={true}
          name="Helmet with a golden leaf"
        />
        <Item
          isPacked={false}
          name="Photo of Tam"
        />
      </ul>
    </section>
  );
}

^ isPacked prop이 true이면 이 코드는 다른 JSX 트리를 반환

 

✔️ 조건부로 null을 사용하여 아무것도 반환하지 않기

컴포넌트는 반드시 무언가를 반환하여야 하는데, 아무것도 반환하고 싶지 않을 때에는

return null;

ㄴ 흔한 경우는 아님

 

✔️ 삼항 조건 연산자 (? : )

return (
  <li className="item">
    {isPacked ? name + ' ✅' : name}
  </li>
);

^ isPacked가 참이면 (?) name + ' ✔'을 렌더링하고, 그렇지 않으면 (:) name을 렌더링

 

✔️ 논리 AND 연산자 (&&)

A && B

  • A가 true이면 B를 결과값으로 선택
  • A가 false이면 A를 결과값으로 선택

* A를 boolean 값으로 만들기

return (
  <li className="item">
    {name} {isPacked && '✅'}
  </li>
);

^ isPacked이면 이름과 함께 체크 표시를 렌더링, 그렇지 않으면 이름 외에는 렌더링하지 않음

 

✔️ 변수에 조건부로 JSX를 할당하기

if문과 변수를 사용하는 방법도 O

* let으로 정의된 변수는 재할당 가능

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✅";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item
          isPacked={true}
          name="Space suit"
        />
        <Item
          isPacked={true}
          name="Helmet with a golden leaf"
        />
        <Item
          isPacked={false}
          name="Photo of Tam"
        />
      </ul>
    </section>
  );
}

 

 

 


리스트 렌더링

React에서 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>

^ 내용이 있는 리스트가 있다고 가정

 

배열에서 항목 리스트를 생성하는 방법

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'
];

 

2. people의 요소를 새로운 JSX 노드 배열인 listItems에 매핑

const listItems = people.map(person => <li>{person}</li>);

 

3. <ul>로 래핑된 컴포넌트의 listItems를 반환

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',
}, {
  id: 3,
  name: 'Percy Lavon Julian',
  profession: 'chemist',
}, {
  id: 4,
  name: 'Subrahmanyan Chandrasekhar',
  profession: 'astrophysicist',
}];

 

위 데이터에서, 직업이 chemist인 항목만 필터링하는 과정

1. people에서 filter()를 호출해 person.profession === 'chemist'로 필터링해서 "chemist"로만 구성된 새로운 배열 chemists를 생성

const chemists = people.filter(person =>
  person.profession === 'chemist'
);

 

2. 이제 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>
);

 

3. 마지막으로 컴포넌트에서 listItems를 반환

return <ul>{listItems}</ul>;

 

* 화살표 함수는 암시적으로 => 바로 뒤에 식을 반환하기 때문에 return문이 필요하지 않음

const listItems = chemists.map(person =>
  <li>...</li> // 암시적 반환!
);

 

* 하지만 => 뒤에 중괄호가 오는 경우 return을 명시적으로 작성해야 함

const listItems = chemists.map(person => { // 중괄호
  return <li>...</li>;
});

 

✔️ key를 사용해서 리스트 항목을 순서대로 유지하기

각 배열 항목에 다른 항목 중에서 교유하게 식별할 수 있는 문자열 또는 숫자를 key로 지정해야 함

<li key={person.id}>...</li>

 

* map() 호출 내부의 JSX 엘리먼트에는 항상 key가 필요함

Key는 각 컴포넌트가 어떤 배열 항목에 해당하는지 React에 알려주어 나중에 일치시킬 수 있도록 함

 

✔️ key를 가져오는 곳

데이터 소스마다 다른 key 소스를 제공

  • 데이터베이스의 데이터: DB에서 데이터를 가져오는 경우, 본질적으로 고유한 DB의 key/ID를 사용할 수 있음
  • 로컬에서 생성된 데이터: 데이터가 로컬에서 생성되고 유지되는 경우, 항목을 만들 때 증분 일련번호나 crypto.randomUUID() 또는 uuid 같은 패키지를 사용해야 함

 

✔️ key 규칙

  • key는 형제 간에 고유해야 함
  • key는 변경되어서는 안 됨 

 

 

 


컴포넌트를 순수하게 유지하기 

순수 함수: 오직 연산만을 수행하는 함수
컴포넌트를 엄격하게 순수 함수로만 작성하면 코드베이스의 규모가 커지더라도 버그를 피할 수 있음

 

✔️ 순수성: 수식으로서의 컴포넌트

순수 함수의 특징

  • 자신의 일에만 집중 ㅡ 함수가 호출되기 전에 존재했던 어떤 객체나 변수를 변경하지 않음 
  • 같은 입력, 같은 출력 ㅡ 같은 입력이 주어졌다면 순수 함수는 항상 같은 결과를 반환

 

React는 모든 컴포넌트가 순수 함수라고 가정

--> React 컴포넌트에 같은 입력이 주어진다면 늘 같은 JSX를 반환한다는 것을 의미 

 

✔️ 사이드 이펙트: 의도하지 (않은) 결과

React의 렌더링 과정은 항상 순수해야 함

ㄴ 컴포넌트는 JSX만 반환해야 하며, 렌더링 이전에 존재했던 어떤 객체나 변수도 변경해서는 안 됨

 

let guest = 0;

function Cup() {
  // 나쁜 지점: 이미 존재했던 변수를 변경하고 있습니다!
  guest = guest + 1;
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  );
}

^ 그러한 규칙을 위반하는 컴포넌트

 

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1} />
      <Cup guest={2} />
      <Cup guest={3} />
    </>
  );
}

^ guest 변수를 Prop으로 넘겨 컴포넌트를 수정 

 

✔️ 지역 변경: 컴포넌트의 작은 비밀

위 예시에서의 문제는 컴포넌트가 기존 변수를 렌더링 중에 변경했다는 것

그러나 이는 외부 변수를 변경했기 때문이고, 함수 내부 변수를 변경하는 것은 상관하지 않음 

= 지역 변경은 OK

 

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaGathering() {
  const cups = [];
  for (let i = 1; i <= 12; i++) {
    cups.push(<Cup key={i} guest={i} />);
  }
  return cups;
}

^ cups 변수나 [] 배열이 ToGathering 내부에서 생성되었기 때문에 괜찮음 

 

✔️ 사이드 이펙트를 일으킬 수 있는 지점

사이드 이펙트 : 화면을 업데이트하고, 애니메이션을 시작하고, 데이터를 변경하는 변화들 

ㄴ 렌더링 중에 발생하는 것이 아니라 '사이드에서' 발생하는 현상 

 

React는 렌더링 중에 사이드 이펙트가 일어나는 것을 좋아하지 않음

--> 사이드 이펙트는 보통 이벤트 핸들러 내부에 위치

ㄴ 이벤트 핸들러는 사용자가 클릭하는 등의 행동을 했을 때만 실행됨 

--> 이벤트 핸들러는 순수할 필요 X

 

사이드 이펙트를 처리할 적합한 이벤트 핸들러를 찾지 못했다면 즉, 사용자 조작 없이 화면이 나타나자마자 자동으로 일어나야 한다면

컴포넌트에서 useEffect를 호출해 반환된 JSX에 해당 사이드 이펙트를 연결 가능 

ㄴ React가 렌더링을 마치고 사이드 이펙트가 허용된 시점에 그것을 실행하도록 만듦

 

* useEffect는 최후의 수단이어야 함

데이터 흐름을 추적하기 어렵게 만들고, 리렌더링이 자주 발생하고, 무한 루프에 빠지기 좋기 때문 

'React > 공식 문서' 카테고리의 다른 글

useReducer  (0) 2026.05.21
상태 구조 설계와 공유  (0) 2026.05.07
불변 업데이트 패턴  (0) 2026.04.28
렌더링과 State 업데이트  (0) 2026.04.08
이벤트 처리와 State  (0) 2026.04.02