[React] Props 이해하기

별이·2025년 2월 10일

React의 핵심 개념 중 하나인 props. 단순히 데이터를 전달한다는 개념은 이해했지만 더 깊이 있게 이해하고 제대로 활용하기 위해 props에 대해 차근차근 정리해 보려 한다.

🔎 Props란?

props는 속성(properties)의 줄임말로, 컴포넌트 간에 데이터 전달을 가능하게 해준다. 즉, 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용되는 일종의 다리 역할을 한다.

props의 중요한 특징은 읽기 전용(read-only)이라는 점이다. 자식 컴포넌트는 전달받은 props를 읽을 수만 있고 직접 변경할 수 없다. 이러한 단방향 데이터 흐름으로 애플리케이션의 상태 변화를 예측 가능하게 만들어 디버깅과 유지 보수를 수월하게 한다.

컴포넌트를 재사용 가능한 독립적인 부품이라고 생각한다면, props는 이 부품을 커스터마이징 할 수 있게 해주는 설정값이다. 문자열이나 숫자뿐만 아니라 함수, 객체, 배열, 다른 컴포넌트까지 다양한 형태의 데이터를 전달할 수 있어 버튼의 텍스트나 색상과 같은 간단한 속성부터 복잡한 데이터 구조까지 자유롭게 전달할 수 있다.

💡 Props 기본 사용법

props 전달 방법

props를 전달하는 가장 기본적인 방법은 HTML 속성을 작성하는 것과 비슷하다. 부모 컴포넌트에서 자식 컴포넌트로 전달하고자 하는 값을 속성 형태로 작성하면 된다. 이때 문자열은 따옴표로 감싸서 전달하고, 숫자나 객체, 배열 등은 중괄호를 사용하여 전달한다.

// 부모 컴포넌트
function Parent() {
	return (
    	<Child name="Byul" age={26} />
    );
}

// 자식 컴포넌트
function Child(props) {
	return (
    	<div>
      		<p>name: {props.name}</p>
			<p>age: {props.age}</p>
      	</div>
    );
}

비구조화 할당으로 Props 사용하기

props를 좀 더 편리하게 사용하는 방법으로 비구조화 할당이 있다. 매번 props.name, props.age와 같이 props를 반복해서 입력하는 대신, 함수의 매개변수에서 중괄호를 사용하여 필요한 값들을 추출할 수 있다.

function Child({ name, age }) {
	return (
    	<div>
      		<p>name: {name}</p>
			<p>age: {age}</p>
      	</div>
    );
}

defaultProps로 기본값 설정하기

컴포넌트에 props가 전달되지 않았을 때를 대비하여 기본값을 설정할 수 있는데, defaultProps를 사용하거나 함수 매개변수에서 기본값을 직접 설정하면 된다.

function Button({ text = '클릭', color = 'pink' }) {
	return (
    	<button style={{ backgroundColor: color }} >{text}</button>
    );
}

// or
Button.defaultProps = {
	text: '클릭',
  	color: 'pink'
};

props.children으로 컴포넌트 합성하기

props.children은 컴포넌트의 여는 태그와 닫는 태그 사이의 내용을 가리킨다. 이를 활용하면 컴포넌트를 감싸는 래퍼(Wrapper) 컴포넌트를 만들거나 레이아웃을 구성할 때 유용하다.

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

function App() {
	return (
    	<Card>
      		<h2>제목</h2>
      		<p>내용입니다.</p>
      	</Card>
    );
}

💡 Props 활용하기

Props vs State 비교

Props와 State는 모두 컴포넌트의 데이터를 다루는 데 사용되지만 서로 다른 목적을 가졌다. Props는 부모 컴포넌트로부터 전달받는 읽기 전용 데이터인 반면, State는 컴포넌트 내부에서 관리되는 변경 가능한 데이터이다. Props는 컴포넌트의 구성 요소를 설정하는 데 사용되고, State는 사용자 상호작용이나 네트워크 응답과 같은 변경되는 데이터를 관리하는 데 사용된다.

Props로 State 전달하기

state를 props로 전달할 수 있다. 이는 부모 컴포넌트의 상태를 자식 컴포넌트와 공유하고 싶을 때 유용하며, state 변경 함수도 함께 전달하여 자식 컴포넌트에서 부모의 상태를 제어할 수 있게 해준다.
state를 props로 전달하면 부모 컴포넌트의 state가 변경될 때마다 자식 컴포넌트도 자동으로 리렌더링 되어 업데이트된 값을 표시한다.

// 부모 컴포넌트
function Parent() {
	const [count, setCount] = useState(0);
  
  	return (
    	<div>
      		<Child
      			count={count} // state를 props로 전달
				onIncrease={() => setCount(count + 1)} // state 변경 함수도 전달
      		/>
      	</div>
    );
}

// 자식 컴포넌트
function Child({ count, onIncrease }) {
	return (
    	<div>
      		<p>현재 카운트: {count}</p>
			<button onClick={onIncrease}>증가</button>
      	</div>
    );
}

스프레드 연산자를 활용한 props 전달

스프레드 연산자(...)를 사용하면 여러 props를 한 번에 전달할 수 있다. 특히 많은 props를 전달해야 하거나, props를 그대로 하위 컴포넌트에 전달해야 할 때 유용하다.

function UserProfile() {
	const userInfo = {
    	name: "Byul",
      	age: 26,
      	email: "byeol@example.com"
    };
  
  	return <UserCard {...useInfo} />;
};

💡 Props 사용 시 주의사항

Props 불변성 지키기

props는 불변성을 유지해야 한다. 즉, 자식 컴포넌트에서 전달받은 props를 직접 수정해서는 안 된다. 대신 부모 컴포넌트에서 상태를 변경하고, 그 변경된 값을 props로 다시 전달받아야 한다.

// ❌ 잘못된 사용
function UserProfile({ user }) {
	user.name = "New Name"; // props 직접 수정하면 안 됨!
  	return <div>{user.name}</div>
}

// ⭕️ 올바른 사용
function UserProfile({ user, onUpdateUser }) {
  	return (
    	<button onClick={() => onUpdateUser({ ...user, name: "New Name" })}>
      		{user.name}
      	</button>
    );
}

Prop Drilling

컴포넌트 계층 구조가 깊어질수록 상위 컴포넌트의 데이터를 하위 컴포넌트로 전달하기 위해 중간 컴포넌트들이 props를 단순히 통과시키기만 하는 현상이 발생할 수 있다. 이를 Prop Drilling이라고 하며, 코드의 유지 보수를 어렵게 만들 수 있다. 이는 Context API를 사용하여 해결할 수 있다.

객체나 배열을 props로 전달할 때의 주의사항

// ❌ 매번 새로운 객체 생성 - 불필요한 리렌더링 발생
<UserProfile user={{ name: "Byul", age: 26 }} />

// ⭕️ 상태로 관리하여 전달
const [user] = useState({ name: "Byul", age: 26 });
<UserProfile user={user} />
profile
💭

0개의 댓글