Describing the UI - Passing Props to a Component

hyocho·2023년 5월 22일
0

React

목록 보기
16/24
post-thumbnail

출처 : https://react.dev/learn/passing-props-to-a-component

리액트 컴포넌트는 서로 통신하는 데에 props를 사용한다. 모든 부모 컴포넌트는 어떤 정보를 그 자식 컴포넌트에게 props를 전달하는 것으로 전달할 수 있다. Props는 HTML 속성을 떠올리게 할 지 모르지만, 객체, 배열, 함수를 포함하는 어떠한 자바스크립트 값도 전달할 수 있다.

배울 것

  • 컴포넌트에 props를 전달하는 방법
  • 컴포넌트에서 props를 읽는 방법
  • props의 기본 값을 정하는 방법
  • 컴포넌트에 JSX를 전달하는 방법
  • 시간에 따른 props의 변경 방법

Familiar props

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

//@App.js
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는 미리 정의되어 있다. (React DOM은 HTML 표준을 준수한다.) 하지만 커스텀하기 위해 <Avatart>와 같은 컴포넌트에는 어떠한 props도 전달할 수 있다.

Passing props to a component

이 코드에서 Profile컴포넌트는 그 자식 컴포넌트인 Avatar로 어떠한 props도 전달하지 않는다.

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

두 가지 과정을 거쳐서 props를 전달할 수 있다.

Step 1: Pass props to the child component

첫째로 Avatar에 props를 전달해라. 예를 들어, person이라는 객체와 size라는 숫자를 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

Avatar 함수 바로 뒤에 있는 ({, }) 안의 콤마로 구분된 person``size 의 이름을 나열하여 이러한 props를 읽을 수 있다. 이것은 변수를 사용하는 것처럼 Avatar 코드 안에서 그것들을 사용할 수 있게 된다.

렌더링을 위해 Avatarperson, size props를 사용하는 로직을 더하면 끝이다.

이제 다양한 props로 다양한 방법으로 렌더링 하도록 Avatar를 구성할 수 있다.

props는 부모 컴포넌트와 자식 컴포넌트를 독립적으로 생각할 수 있게 해준다. 예를 들어, Avatar가 사용하는 방법을 고려하지 않고도 Profile내에서 person이나 size를 변경할 수 있다. 유사하게, Profile을 보지 않고도 Avatar가 이러한 props를 사용하는 방법을 변경할 수 있다.

props는 스스로 조정할 수 있는 "knobs"같은 것과 같은 것으로 생각할 수 있다. 그것들은 함수에 대한 인수 역할과 동일한 역할을 한다. 실제로 props는 컴포넌트의 유일한 인자이다. 리액트 컴포넌트 함수는 단일 인수인 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 }) {
  // ...

이제 만약 <Avatar person={...} /> size prop 없이 렌더링 되면, size100으로 지정될 것이다.

기본 값은 size prop이 없거나, 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도 직접 사용하지 않기 때문에 더 간결한 "전개" 문법을 사용하는 것이 의미 있을 수 있다.

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

그러면 Profile의 모든 props가 이름을 나열하지 않고 Avatar로 전달된다.

제한이 있는 전개 문법을 사용하라. 만약 당신이 그것을 다른 모든 컴포넌트에서 사용하고 있다면, 뭔가 잘못된 것이다. 종종 컴포넌트를 쪼개고 children을 JSX로 전달해야 한다.

Passing JSX as children

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

<div>
  <img />
</div>

JSX 태그 안에서 콘텐츠를 중첩시키면, 부모 컴포넌트는 children이라고 불리는 prop을 받는다. 예를 들어, 아래의 Card 컴포넌트는 Avatar로 설정된 children prop을 받아서 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컴포넌트가 중첩된 컨텐츠를 어떻게 랩핑할 수 있는지 확인하려면 <Card>안에 <Avatar>를 일부 텍스트로 대체해 보면 된다. 내부에서 렌더링되는 내용을 "알" 필요는 없다. 이러한 유연한 패턴을 많은 곳에서 볼 수 있을 것이다.

children prop을 가지고 있는 컴포넌트를 임의의 JSX로 부모 컴포넌트에 의해 "채울 수 있는" "구멍" 이 있다고 생각할 수 있다. 시각적인 wrapper (panels, grid 등) 를 children prop으로 사용할 경우가 종종 있을 것이다.

How props change over time

아래의 Clock 컴포넌트는 부모 컴포넌트로부터 color, time 이라는 두 개의 prop을 전달 받는다. ( 부모 컴포넌트의 코드는 생략한다)

아래 셀렉트 박스에서 컬러를 바꾸려고 해봐라.

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

이 예시는 컴포넌트가 시간이 지남에 따라 다른 props를 받을 수 있다는 것을 보여준다. props가 항상 정적인 것은 아니다! 여기 time prop은 1초마다 변경되며, 다른 색을 선택하면 color prop이 변경된다. props는 컴포넌트 처음의 데이터만 반영하는 것이 아니라 특정 시점에 반영한다.

하지만, props는 불변성을 가진다. 컴퓨터 과학적인 의미로 "변화하지 않는" 이라는 뜻을 의미한다. 컴포넌트가 props를 변경해야 할 경우 (예를 들어, 유저 상호작용이나 새로운 데이터에 대한 응답), 부모 컴포넌트가 다른 props - 새 객체 - 를 전달하도록 "요청" 해야 한다. 오래된 props는 버려지고, 결국 자바스크립트 엔진은 그들이 가져간 메모리를 회수할 것이다.

props를 바꾸려고 하지 마라. 선택한 색상을 변경하는 것과 같이 사용자 입력에 대해 응답해야 할 때는 State: A Component’s Memory 에서 배운 "set State"를 사용해야 한다.

RECAP

  • HTML속성과 마찬가지로 props를 전달하기 위해 JSX에 추가한다.
  • props를 읽으려면 구조 분해 할당 문법을 사용한다.
  • 누락되거나 undefined props에 props의 기본값을 지정할 수 있다.
  • 전개 연산자로 모든 props를 전달할 수 있지만, 과도하게 사용하지 말 것.
  • 중첩된 JSX가 children prop으로 나타난다.
  • props는 읽기 전용 스냅샷으로, 모든 렌더링은 새로운 버전의 props를 받는다.
  • props는 변경시킬 수 없다. 상호작용이 필요할 때는 상태를 설정해야 한다.
profile
기록하는 습관을 기르고 있습니다.

0개의 댓글