[리액트 공식문서 읽기] DESCRIBING THE UI - Passing Props to a Component

JaeHong Jeong·2023년 8월 17일
post-thumbnail

Overview

리액트는 props를 통해 소통한다. 모든 부모 컴포넌트는 props로 자식 컴포넌트들에게 정보를 전달할 수 있다. Props는 HTML 속성을 상기시킬 수 있지만 개체, 배열 및 함수를 포함하여 이를 통해 모든 JavaScript 값을 전달할 수 있다.

Familiar props

Props는 JSX태그에 전달하는 정보이다. 예를 들어 className, src, alt, width, height<img> 에 전달할 수 있는 props이다

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 />
  );
}

<img> 태그에 전달할 수 있는 소품은 미리 정의되어 있습니다(the HTML standard). 하지만 그러나 <Avatar>와 같은 자신의 구성 요소에 소품을 전달하여 사용자 정의할 수 있다. 방법은 다음과 같다

Passing props to a component

Profile 컴포넌트는 자식 컴포넌트인 Avatar 에게 아무 props도 전달하지 않는다.

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

두 단계로 Avatar props를 줄 수 있다.

You can give Avatar some props in two steps.

Step 1: Pass props to the child component

첫번째, Avatar 에 props를 전달한다. 예를 들어 person (객체)와 size (숫자)를 전달하자

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

person= 뒤의 이중 중괄호가 혼란스러우면 JSX 중괄호 안의 객체일 뿐임을 상기해라

이제 Avatar 컴포넌트 내에서 이러한 소품을 읽을 수 있다.

Step 2: Read props inside the child component

Avatar함수 바로 뒤에 쉼표({})로 구분된 사람 person, size를 나열하여 이러한 props를 읽을 수 있다. 이렇게 하면 변수와 마찬가지로 Avatar코드 내에서 사용할 수 있다.

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

렌더링을 위해 personsize props를 사용하는 일부 논리를 Avatar에 추가하면 완료된다.

이제 다양한 props를 사용하여 다양한 방식으로 렌더링하도록 Avatar를 구성할 수 있습니다. 값을 조정해보아라

// App.js
import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi', 
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'Aklilu Lemma', 
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{ 
          name: 'Lin Lanying',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}
// utils.js
export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}

Props를 사용하면 자식과 부모 컴포넌트를 독립적으로 생각할 수 있다. 예를 들어, Avatar 가 어떻게 사용하는지 생각할 필요 없이 Profile 에서 person 이나 size props을 변경할 수 있다. 마찬가지로 Profile 을 보지 않고 Avatar 가 이러한 props를 사용하는 방법을 변경할 수 있다.

props를 조정할 수 있는 ‘손잡이’와 같이 생각할 수 있다. 인수가 함수에게 제공하는 것과 동일한 역할을 한다. 실제로 props는 컴포넌트에 대한 유일한 인수이다. 리액트 컴포넌트 함수는 단일 인수인 props 객체를 허용한다.

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

일반적으로 전체 props 객체 자체가 필요하지 않으므로 이를 개별 props로 분해한다.

💡 Pitfall

props를 선언할 때 () 안의 {} 중괄호 쌍을 놓지지 말아라

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

이 구문은 ‘구조 분해 할당’이라고 하며 함수 매개변수에서 속성을 읽는 것과 동일하다.

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

Specifying a default value for a prop

값이 지정되지 않았을 때 대체할 기본값을 props에 지정하려면 매개변수 바로 뒤에 =와 기본값을 넣어 구조 분해를 수행할 수 있다.

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

이제 <Avatar person={...} />size props 없이 렌더링 되면 size100 으로 설정된다..

기본값은 size props가 누락되었거나 size={undefined}를 전달한 경우에만 사용된다. 그러나 size={null} 또는 size={0} 를 전달하면 기본값이 사용되지 않는다.

Forwarding props with the JSX spread syntax

때때로 전달되는 props는 매우 반복적이다.

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

반복되는 코드에 문제가 있는 것은 아니다. 더 쉽게 읽을 수도 있다. 하지만 간결함을 중시할 수 있다. 일부 컴포넌트는 ProfileAvatar 에서 수행하는 방식과 같이 모든 props를 자식에게 전달한다. props를 직접 하용 하지 않기 때문에 보다 간결한 ‘spread’ 문법을 사용하는 것이 좋다.

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

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

제한적으로 spread 문법을 사용해라. 다른 모든 컴포넌트에 사용하면 문제가 있을 것이다. 컴포넌트를 분할하고 자식을 JSX로 전달해야 하기 때문이다. 다음에 더 자세히 알아보자

Passing JSX as children

내장 브라우저 태그를 중첩하는 것이 일반적이다.

<div>
  <img />
</div>

때로는 이런 방식으로 자신의 컴포넌트를 중첩하고 싶을 수 있다.

<Card>
  <Avatar />
</Card>

JSX태그 안에 컨텐츠를 중첩하면 부모 컴포넌트는 children 이라는 props에서 해당 컨텐츠를 받는다. 예를 들어 아래의 Card 컴포넌트는 <Avatar /> 로 설정된 children props를 수신하고 감싸는 div에서 렌더링한다.

// App.js
import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

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

export default function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}
// utils.js
export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}

<Card> 내부의 <Avatar> 를 일부 텍스로 교체하여 <Card> 컴포넌트가 중첩된 컨텐츠를 래핑하는 방법을 확인해라. 내부에 렌더링되는 내용을 알필요가 없다. 이 유연한 패턴은 여러 곳에서 볼 수 있다.

children props가 있는 컴포넌트는 임의의 JSX를 사용하여 부모 컴포넌트에 의해 “채워질” 수 있는 “구멍”이 있는 것으로 생각할 수 있다. 패널, 그리드 등의 시각적 래퍼에 children 을 자주 사용한다.

How props change over time

Clock 컴포넌트는 부모 컴포넌트로부터 colortime 두 가지 속성을 받는다.

export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

이 예제는 컴포넌트가 시간이 지남에 따라 다른 props를 받을 수 있음을 보여준다. props가 항상 정적이지 않다. 여기에서 time props는 1초마다 변경되고 color props는 다른 색상을 선택하면 변경된다. Props는 처음이 아니라 어느 시점에서나 컴포넌트의 데이터를 반영한다.

하지만 props는 불변하다. 컴퓨터 과학 용어는 ‘변경할 수 없음’을 의미한다. 컴포넌트가 props를 변경해야 할 때 (예를 들어 사용 interaction이나 새로운 데이터에 대한 응답) 부모 컴포넌트에 다른 props를 전달하도록 ‘요청’해야 한다. 그런 다음 이전 props는 폐기되고 결국 JavaScript 엔진은 props가 가져간 메모리를 회수한다.

‘Props 변경을 시도하지마라’. 사용자 입력에 응답해야 하는 경우 (색상 변경 같은), ‘set state’가 필요하며 이는 State: A Component’s Memory.에서 배울 수 있다.

Recap

  • props를 전달하려면 HTML 속성과 마찬가지로 JSX에 추가해라.
  • props를 읽으려면 function Avatar({ person, size }) 구조 분해 구문을 사용해라.
  • 누락되고 정의되지 않은 props에 사용되는 size = 100 과 같이 기본값을 지정할 수 있다.
  • <Avatar {...props} /> JSX spread 구분으로 모든 props를 전달할 수 있지만 과도하게 사용하지 마라
  • <Card><Avatar /></Card> 와 같이 중첩된 JSX는 Card 컴포넌트의 children 로 나탄다.
  • props는 시간에 따른 읽지 전용 스냅샷이다. 모든 렌더링은 새로운 버전의 props를 받는다.
  • props를 변경할 수 없다. interactivity가 필요한 경우 state 설정을 해야한다.
profile
반갑습니다.

0개의 댓글