React 7. Passing Props to a Component

뚜루미·2024년 2월 27일

React

목록 보기
7/39
post-thumbnail

React 컴포넌트는 props를 사용하여 서로 통신합니다. 모든 상위 컴포넌트는 props를 제공하여 하위 컴포넌트에 일부 정보를 전달할 수 있습니다. props는 HTML 속성뿐만 아니라 객체, 배열 및 함수를 포함한 모든 JavaScript 값을 전달할 수 있습니다.

Familiar props

props는 JSX 태그를 전달하는 정보입니다. 예를 들어, className, src, alt, widthheight<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> 에 전달되는 props들은 미리 정의되어 잇습니다. (ReactDOM은 HTML 표준을 따릅니다.) 하지만 props를 <Avatar> 와 같은 자체 컴포넌트에 전달하여 사용자 정의할 수 있습니다.

Passing props to a component

아래 코드를 보면, Profile 컴포넌트는 Avatar 컴포넌트에 아무 props를 전달하지 않습니다.

Step 1: Pass props to the child component

먼저, Avatar 에 props를 전달합니다.

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

🗒️ 이중 중괄호 person은 JSX 괄호 내의 객체입니다.

Step 2: Read props inside the child component

function Avatar 바로 뒤에 ({)} 로 구분되어 나열된 personsize를 props로 읽을 수 있습니다. 이는 변수로써 Avatar 코드내에서 사용할 수 있습니다.

몇가지 로직을 Avatar안에 추가하여 personsize props를 렌더링하는 데 사용할 수 있습니다.

// utils.js
export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}

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

props를 사용하면 부모 및 자식 컴포넌트를 독립적으로 생각할 수 있습니다. 예를 들어, Avater 에서 내부 props를 어떻게 사용하는지 생각할 필요 없이 Profile 내부의 personsize props를 변경할수 있습니다. 유사하게, Profile을 보지 않고도 Avatar에서 이러한 props를 변경할 수 있습니다.

이를 조정할 수 있는 손잡이와 같은 props를 생각해볼 수 있습니다. props들은 함수에서 매개변수와 같은 역할을 합니다. 실제로, props는 컴포넌트의 유일한 매개변수입니다. React 컴포넌트 함수에서 받을 수 있는 유일한 매개변수는 props 객체입니다.

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

일반적으로 props 객체 전체는 필요하지 않기 때문에 개별 props로 구조화합니다.

🚨 props를 선언할 때 ( ) 안에 { } 를 반드시 넣어야 합니다.

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

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

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

Specifying a default value for a prop

만약 prop에 기본 값을 지정하려면 매개변수 바로 뒤에 = 기호를 넣어서 구조 분해 할당을 수행하면 됩니다.

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

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

기본 값은 size prop이 없거나 size={undefined} or size={null}을 전달할 경우에만 사용됩니다. 그러나 size={0}를 전달하면 기본값은 사용되지 않습니다.

Forwarding props with the JSX spread syntax

때로는 prop 전달이 여러번 반복되는 경우가 있습니다.

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

반복적인 코드에는 문제가 없고 더 쉽게 읽을 수 있지만 때로는 간결함이 더 중요할 수 있습니다. Profile와 같은 일부 컴포넌트는 모든 props를 Avatar 하위 항목을 전달합니다. props를 직접 사용하지 않기 때문에 보다 간결한 spread 구문을 사용하는 것이 합리적일 수 있습니다.

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

각 props을 나열하지 않고 모든 Profile props가 Avatar 에 전달됩니다.

spread 구문을 사용할 때는 제한을 두어야 합니다. 다른 모든 컴포넌트에서 이를 사용하는 경우는 뭔가 잘못된 것입니다. 종종 이는 컴포넌트를 분할하고 하위 항목을 JSX로 전달해야 함을 나타냅니다.

Passing JSX as children

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

<div>
	<img />
</div>

때로는 같은 방식으로 사용자 정의 컴포넌트를 중첩할 수 있습니다.

<Card>
  <Avatar />
</Card>

JSX 태그 내에 컨텐츠를 중첩하면 상위 컴포넌트는 children이라는 prop을 받게 됩니다. 예를 들어, 아래 Card 컴포넌트는 children prop set을 받고 <Avatar />를 세팅하고 wrapper 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> 의 텍스트를 변경하면 됩니다. 내부가 어떻게 렌더링하는지 알 필요 없으며 이러한 유연한 패턴은 여러 곳에서 볼 수 있습니다.

children prop이 있는 컴포넌트는 임의의 JSX를 사용하여 상위 컴포넌트에 의하여 채워질 수 있는 구멍이 있는 것으로 생각할 수 있습니다. 시각적 wrapper(panel, grid 등)에 children prop을 자주 사용하게 됩니다.

How props change over time

아래 Clock 컴포넌트는 상위 컴포넌트로 부터 두 개의 props (colortime)을 받습니다.

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

이는 컴포넌트가 시간이 지남에 따라 다른 prop을 받을 수 있음을 보여줍니다. prop은 항상 정적이지 않습니다. 여기서 time 컴포넌트는 1초마다 바뀌는데, 다른 색상을 선택하면 color prop이 바뀌게 됩니다. props는 초기 컴포넌트의 데이터만이 아닌 특정 시점의 컴포넌트 데이터를 반영합니다.

그러나, props는 immutable합니다. 즉, 변경할 수 없습니다. 컴포넌트가 props를 변경해야 하는 경우(예: 사용자 상호작용 또는 새 데이터에 대한 응답) 상위 컴포넌트의 다른 props, 즉 새 객체를 전달하다록 요청해야 합니다. 그런 다음 오래된 props는 폐기되고 결국 JavaScript 엔진은 해당 props가 차지한 메모리를 회수하게 됩니다.

props 변경을 시도해선 안됩니다. 사용자 입력에 응답해야 하는 경우 “set state”가 필요합니다.

0개의 댓글