props는 React 컴포넌트의 입력값입니다. 부모가 JSX에서 <UserCard name="Ada" online={true} />처럼 속성으로 넘기면, 자식은 하나의 객체로 받으며 보통 함수의 매개변수에서 구조 분해합니다. props 덕분에 하나의 컴포넌트가 사용할 때마다 다른 데이터를 보여 줄 수 있습니다.
같은 UserCard가 서로 다른 세 사람을 렌더링합니다. 마지막 카드를 보세요. 값이 없는 속성 online은 online={true}를 뜻합니다. 자기 이름과 역할로 네 번째 카드를 추가해 보세요.
props 전달하고 읽기
문자열은 따옴표로, 그 밖의 값은 중괄호로 넘깁니다. 숫자, 불리언, 배열, 객체, 함수, 심지어 JSX도 가능합니다.
<Product
title="Desk lamp"
price={39.5}
inStock={false}
tags={['light', 'office']}
seller={{ name: 'Lumen', rating: 4.8 }}
/>
React는 모든 속성을 하나의 객체로 모아 컴포넌트의 첫 번째 인자로 넘깁니다. 이것을 props로 읽어도 되고, 매개변수 목록에서 필요한 필드만 바로 꺼내도 됩니다.
function Product(props) {
return <h3>{props.title}</h3>;
}
function Product({ title, price, seller }) {
return <h3>{title}, ${price} from {seller.name}</h3>;
}
두 버전 모두 같은 객체를 받습니다. 구조 분해를 쓰면 함수 시그니처에 컴포넌트가 사용하는 props가 정확히 나열되므로 이 방식이 흔히 쓰입니다.
기본값
prop에 기본값을 주려면 자바스크립트의 구조 분해 기본값 = value를 사용합니다. 부모가 prop을 생략하거나 undefined를 넘길 때 적용됩니다. 실제 값인 null, 0, false, ''에는 적용되지 않습니다.
처음 세 버튼은 prop이 없거나 undefined인 곳에서 기본값을 사용합니다. 마지막 버튼은 null을 넘기므로 size는 정말로 null이 되고, 조회 결과 패딩을 찾지 못합니다. size={null}을 size="small"로 바꾸면 해결됩니다.
오래된 코드는 정적 속성 Button.defaultProps = { size: 'medium' }로 기본값을 설정합니다. React 19는 함수 컴포넌트에서 defaultProps를 제거했습니다. JSX는 함수에 붙은 이 속성을 경고 없이 무시합니다. 클래스 컴포넌트에서는 여전히 동작합니다. 구조 분해 기본값을 사용하세요.
함수를 props로 전달하기
데이터는 아래로 흐릅니다. 부모가 자식에게 props를 넘기며, 반대 방향은 없습니다. 자식이 부모에게 무언가 일어났다고 알려야 할 때는 부모가 함수를 넘기고 자식이 그 함수를 호출합니다. 관례상 이런 props의 이름은 onSomething 형태입니다.
Rating은 아무것도 저장하지 않습니다. 받은 value를 보여 주고 클릭을 onRate로 알릴 뿐입니다. 상태는 App에 있고, App이 그 상태를 다시 아래로 넘깁니다. handleRate 대신 onRate={setRating}을 직접 넘겨도 동작합니다. setter도 함수이기 때문입니다. 이렇게 상태를 공통 부모로 옮기는 것을 상태 끌어올리기라고 합니다.
props 전개하기
키가 컴포넌트의 props와 일치하는 객체를 이미 가지고 있다면, 속성을 하나씩 쓰는 대신 {...object}로 전개하세요. 매개변수 목록의 나머지 문법은 반대로 동작합니다. 몇 개의 props는 이름으로 꺼내고, 나머지를 모두 모아서 그대로 넘깁니다.
두 번째 아바타는 person을 전개한 다음 color를 설정합니다. 같은 prop이 두 번 나오면 나중 것이 이기므로, 덮어쓸 값은 전개 뒤에 두세요. TextField는 label은 자기가 쓰고 type, placeholder, maxLength는 <input>에 그대로 넘깁니다. 전개는 이런 래퍼에 사용하세요. 다른 곳에서는 props를 명시적으로 나열하는 편이 컴포넌트가 무엇을 받는지 알아보기 쉽습니다.
props는 읽기 전용입니다
컴포넌트는 절대로 자기 props를 바꾸면 안 됩니다. props는 부모의 것이고, 같은 객체가 공유될 수도 있습니다. 다시 할당하면 안 되는 함수 인자처럼 다루세요.
function Counter({ count }) {
count = count + 1; // wrong: changes a local copy, the parent never sees it
return <p>{count}</p>;
}
function Profile(props) {
props.name = 'Someone else'; // wrong: in development React freezes props, so this throws a TypeError
return <p>{props.name}</p>;
}
그래도 props는 시간이 지나면서 바뀝니다. 부모가 새 값으로 다시 렌더링하면 자식은 새 props 객체를 받아 그것으로 렌더링합니다.
Temperature는 celsius를 절대 바꾸지 않습니다. 렌더링할 때마다 그 값으로 fahrenheit를 계산합니다. 슬라이더를 움직이면 부모의 상태가 바뀌고, 자식은 새 prop을 받습니다. 자식이 스스로 바꿀 수 있는 값이 필요하다면 그 값은 prop이 아니라 state입니다.
props와 state
props와 state는 모두 컴포넌트가 렌더링하는 내용에 영향을 주는 일반 자바스크립트 값이고, 둘 중 어느 쪽이 바뀌어도 컴포넌트가 다시 렌더링됩니다. 차이는 그 값의 주인이 누구인지입니다.
| Props | State | |
|---|---|---|
| 출처 | 부모, JSX 속성으로 전달 | 컴포넌트 자신, useState 또는 useReducer로 생성 |
| 컴포넌트가 바꿀 수 있나 | 아니요, 읽기 전용 | 네, setter로 변경 |
| 일반적인 용도 | 컴포넌트 설정: 라벨, 크기, 보여 줄 데이터 | 바뀌는 것 기억: 입력 텍스트, 열린 메뉴 |
같은 값이 둘 다인 경우가 많습니다. 위의 온도 예제에서 celsius는 App에서는 state이고 Temperature에서는 prop입니다. 주인은 그 값을 state로 가지고 있다가 prop으로 아래에 넘기며, 자식에게 필요하다면 값을 바꾸는 함수도 함께 넘깁니다.
prop에는 JSX와 컴포넌트를 포함해 어떤 값이든 담을 수 있습니다. icon={<StarIcon />} 같은 요소를 넘기면 부모가 자식 안의 한 자리를 채울 수 있습니다. 이름을 직접 정한 children과 같은 개념입니다.
children prop
컴포넌트의 여는 태그와 닫는 태그 사이에 넣은 것은 무엇이든 children이라는 prop으로 전달됩니다. 이 방법으로 내용을 미리 알지 못하는 카드, 패널, 레이아웃 같은 래퍼를 만듭니다.
children 페이지에서 여러 슬롯을 넘기는 법과 children을 안전하게 다루는 법을 다룹니다.
key는 props가 아닙니다
key는 속성처럼 보이지만, React가 렌더링 사이에 목록 항목을 짝짓기 위해 자기가 보관합니다. 컴포넌트는 이 값을 받지 못합니다.
콘솔에는 props.key가 undefined로, props.id는 실제 값으로 표시됩니다. 자식에게 식별자가 필요하면 여기의 id처럼 다른 이름으로 한 번 더 넘기세요. 개발 빌드에서는 props.key를 읽을 때 경고도 나오지만, 미리보기는 프로덕션 빌드처럼 실행되므로 undefined만 보입니다.
자주 묻는 질문
React에서 props란 무엇인가요?
props(properties의 줄임말)는 컴포넌트의 인자입니다. 부모가 JSX 속성으로 <Avatar size={48} />처럼 넘기면, 자식은 하나의 객체로 받으며 보통 function Avatar({ size })처럼 구조 분해합니다.
prop의 기본값은 어떻게 설정하나요?
구조 분해 기본값을 사용하세요: function Button({ size = 'medium' }). 기본값은 prop이 없거나 undefined일 때 적용됩니다. React 19는 함수 컴포넌트에서 defaultProps를 제거했고, 클래스 컴포넌트는 여전히 지원합니다.
자식 컴포넌트가 자기 props를 바꿀 수 있나요?
아니요. props는 읽기 전용입니다. 자식이 보여 주는 내용을 바꾸려면 부모가 새 props를 넘깁니다. 자식이 변경을 요청하게 하려면 부모가 onChange 같은 함수를 넘기고 자식이 그 함수를 호출합니다.
props와 state의 차이는 무엇인가요?
props는 부모에게서 오며 자식은 바꿀 수 없습니다. state는 컴포넌트 자신에게 속하며 setter로 바뀝니다. 어떤 값이 부모에서는 state이고 자식에서는 prop인 경우가 흔합니다.
props.key가 undefined인 이유는 무엇인가요?
key는 (예전 React의 ref처럼) React 자신이 목록 항목을 추적하는 데 사용하며 컴포넌트에 전달되지 않습니다. 자식에게 그 값이 필요하면 다른 이름으로 한 번 더 넘기세요. 예: <Row key={id} id={id} />.