본문 바로가기
React/Documentation

리액트 공식 문서 번역-05. 컴포넌트에 프롭스 전달하기

by 똘이토스 2023. 7. 9.

React 컴포넌트는 서로 통신하기 위해 props를 사용합니다. 부모 컴포넌트는 자식 컴포넌트에게 props를 제공하여 정보를 전달할 수 있습니다. Props는 HTML 속성을 생각나게 할 수 있지만, 객체, 배열 및 함수를 포함한 JavaScript 값 모두를 props를 통해 전달할 수 있습니다.

 

https://codesandbox.io/s/qdv180?file=/App.js&utm_medium=sandpack

 

stupefied-shadow-qdv180 - CodeSandbox

stupefied-shadow-qdv180 using react, react-dom, react-scripts

codesandbox.io

 

<Img> 태그에 전달할 수 있는 props는 미리 정의되어 있습니다(ReactDOM은 HTML 표준을 준수합니다). 그러나 <Avatar>와 같은 사용자 정의 컴포넌트에는 원하는 props를 전달하여 커스터마이징할 수 있습니다. 아래에서 방법을 살펴보겠습니다!

 

컴포넌트에 props 전달하기

이 코드에서 Profile 컴포넌트는 Avatar 자식 컴포넌트에게 props를 전달하지 않습니다.

 

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

 

Avatar 컴포넌트에 props를 전달하는 두 가지 단계가 있습니다.

 

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

먼저, Avatar에 몇 가지 props를 전달합니다. 예를 들어, person (객체)과 size (숫자) 두 가지 props를 전달해 봅시다.

 

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

 

이제 Avatar 컴포넌트 안에서 이러한 props를 읽을 수 있습니다.

 

Step 2: 자식 컴포넌트 내에서 props 읽기

person, size와 같은 prop 이름들을 ({}) 안에 쉼표로 구분하여 function Avatar 바로 뒤에 작성하면, 이 prop들을 변수처럼 Avatar 코드 안에서 사용할 수 있습니다. Avatar 내에 personsize를 사용하여 렌더링하는 로직을 추가하면 됩니다. 그럼 이제 Avatar를 다양한 방식으로 설정하고 다른 props를 테스트해보세요!

 

function Avatar({ person, size }) {
  // person and size are available here
}

 

이제 Avatar 컴포넌트 내에서 personsize props를 사용하는 로직을 추가하고, 작업이 완료되었습니다.

 

이제 여러 가지 다른 props로 Avatar를 다양한 방식으로 렌더링할 수 있습니다. 값을 조정해보세요!

 

https://codesandbox.io/s/50ekf9?file=/App.js&utm_medium=sandpack

 

cranky-leavitt-50ekf9 - CodeSandbox

cranky-leavitt-50ekf9 using react, react-dom, react-scripts

codesandbox.io

 

Props를 사용하면 부모 컴포넌트와 자식 컴포넌트를 독립적으로 생각할 수 있습니다. 예를 들어, Profile 내에서 person 또는 size props를 변경할 수 있고 Avatar가 이를 사용하는 방식을 생각하지 않아도 됩니다. 마찬가지로, Avatar가 이러한 props를 사용하는 방식을 변경할 수 있습니다. Profile을 보지 않고도 가능합니다.

 

Props는 조정 가능한 "조절기(knobs)"와 같다고 생각할 수 있습니다. 실제로, props는 컴포넌트에 전달되는 유일한 인수입니다! React 컴포넌트 함수는 단일 인수인 props 객체를 받습니다.

 

function Avatar(props) {
  let person = props.person;
  let size = props.size;
  // ...
}

 

 

보통은 단일 props가 아니라 여러 개의 props를 사용하기 때문에, props 객체 전체를 사용하지 않습니다. 따라서 개별적인 props로 구조분해를 수행합니다.

 

props를 선언할 때 () 내부에 {} 한 쌍의 중괄호를 놓치지 마세요

 

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

 

이 구문은 "비구조화(destructuring)"라는 구문이며, 함수 매개변수에서 속성(properties)을 읽는 것과 동일합니다.

 

function Avatar(props) {
  let person = props.person;
  let size = props.size;
  // ...
}

 

prop의 기본값 지정

만약 값이 지정되지 않았을 때 prop에 기본값을 지정하려면, 파라미터 바로 뒤에 = 와 기본값을 넣으면 됩니다. 이를 destructuring을 사용하여 할 수 있습니다. 아래 코드를 참고해주세요.

 

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

 

이제, 만약 <Avatar person={...} />size prop이 없이 렌더링된다면, size100으로 설정됩니다.

 

기본값은 size prop이 누락되거나 size={undefined}를 전달하는 경우에만 사용됩니다. 하지만 size={null} 또는 size={0}을 전달하는 경우에는 기본값이 사용되지 않습니다.

 

JSX 스프레드 구문을 사용하여 props 전달

가끔, props를 전달하는 것이 매우 반복적일 때가 있습니다.

 

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

 

반복적인 코드에는 문제가 없습니다 - 가독성이 높아질 수도 있습니다. 하지만 때로는 간결함을 중요시 할 수도 있습니다. 일부 구성 요소는 Avatar와 같이 Profile에서 수신한 모든 props를 자식 요소에 전달합니다. 직접 사용하지 않으므로 더 간결한 "spread" 구문을 사용하는 것이 더 합리적일 수 있습니다.

 

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

 

이렇게 하면 Profile의 모든 props가 각각의 이름을 나열하지 않고 Avatar로 전달됩니다.

 

전개 구문을 사용할 때는 분별력을 가지고 사용해야 합니다. 다른 컴포넌트에서 이를 사용하고 있다면 문제가 있을 수 있습니다. 이는 종종 컴포넌트를 분할하고 JSX로 자식을 전달해야 한다는 것을 나타냅니다. 이에 대해서는 다음에 더 자세히 알아보겠습니다!

 

JSX를 children으로 전달하기

기본 내장 브라우저 태그를 중첩하는 것이 일반적입니다

 

<div>
  <img />
</div>

 

가끔은 자신이 만든 컴포넌트를 같은 방식으로 중첩시키고 싶을 때가 있습니다.

 

<Card>
  <Avatar />
</Card>

 

JSX 태그 내에 콘텐츠를 중첩하면, 부모 컴포넌트는 children이라는 이름의 prop으로 해당 콘텐츠를 받습니다. 예를 들어, 아래의 Card 컴포넌트는 children prop으로 <Avatar />를 받고, 이를 래퍼 div 내에서 렌더링합니다.

 

https://codesandbox.io/s/r3k9uk?file=/App.js&utm_medium=sandpack

 

flamboyant-hill-r3k9uk - CodeSandbox

flamboyant-hill-r3k9uk using react, react-dom, react-scripts

codesandbox.io

 

<Card> 안에 있는 <Avatar>를 일부 텍스트로 대체해보면, Card 컴포넌트가 어떤 중첩된 내용을 래핑할 수 있는지 볼 수 있습니다. Card가 렌더링할 내용을 알 필요가 없습니다. 이 유연한 패턴은 많은 곳에서 볼 수 있습니다.

 

children prop을 가진 컴포넌트는 부모 컴포넌트에서 임의의 JSX로 "채울" 수 있는 "홀"을 가지고 있는 것으로 생각할 수 있습니다. 종종 children prop을 시각적 래퍼(패널, 그리드 등)에 사용합니다.

 

 

props가 시간이 지남에 따라 어떻게 변하는가

아래의 Clock 컴포넌트는 부모 컴포넌트로부터 colortime이라는 두 개의 props를 받습니다. (상태를 사용하기 때문에 부모 컴포넌트의 코드는 생략되었습니다.)

아래의 select 상자에서 색상을 변경해보세요

 

https://codesandbox.io/s/s7in42?file=/Clock.js&utm_medium=sandpack

 

eloquent-golick-s7in42 - CodeSandbox

eloquent-golick-s7in42 using react, react-dom, react-scripts

codesandbox.io

 

이 예제는 컴포넌트가 시간이 지남에 따라 다른 props를 받을 수 있다는 것을 보여줍니다. Props는 항상 정적이지 않습니다! 여기에서 time props는 매 초마다 변경되고, color props는 다른 색상을 선택할 때 변경됩니다. Props는 컴포넌트의 데이터를 어느 시점에서나 반영합니다.

 

하지만 props는 "불변"이며 (컴퓨터 과학에서의 용어로 "변경할 수 없는"을 의미합니다.), 컴포넌트가 자신의 props를 변경하려고 하면(예를 들어, 사용자 입력 또는 새 데이터에 대한 응답으로), 새 객체를 전달받기 위해 부모 컴포넌트에 "요청"해야 합니다. 그러면 이전 props는 버려지고, 결국 JavaScript 엔진이 그것들이 차지하는 메모리를 회수할 것입니다.

 

props를 변경하지 마세요. 사용자 입력에 대응해야 할 때 (예: 선택된 색상 변경), "상태를 설정"해야 합니다.

 

요약

  • props를 전달하기 위해서는 HTML 속성과 마찬가지로 JSX에 추가하세요.
  • props를 읽기 위해서는 함수 내에서 Avatar({ person, size })와 같이 destructuring 문법을 사용하세요.
  • size=100과 같이 기본값을 지정할 수 있으며, 이는 prop이 없거나 undefined인 경우 사용됩니다.
  • JSX spread syntax인 <Avatar {...props} />를 사용하여 모든 props를 전달할 수 있지만, 지나치게 사용하지 마세요!
  • <Card><Avatar /></Card>와 같이 중첩된 JSX는 Card 컴포넌트의 children prop으로 나타납니다.
  • props는 읽기 전용이며, 모든 렌더링에서 새로운 버전의 props를 받습니다.
  • props를 변경할 수 없습니다. 상호 작용이 필요한 경우 state를 설정해야 합니다.

 

2023.07.09 - [React/Documentation] - 리액트 공식 문서 번역-06. 조건부 렌더링

 

리액트 공식 문서 번역-06. 조건부 렌더링

React에서 컴포넌트는 다양한 조건에 따라 다른 것을 표시해야 할 때가 많습니다. React에서는 if 문, && 연산자, ? : 연산자와 같은 JavaScript 구문을 사용하여 조건부로 JSX를 렌더링할 수 있습니다. 조

ddor2.tistory.com