리액트는 부모에서 → 자식 컴포넌트에게만 데이터를 전달할 수 있음 ⇒ 단방향 데이터 흐름
💡 반면 Vue는 양방향 데이터 바인딩을 지원
Props는 부모 컴포넌트가 자식 컴포넌트로 데이터를 전달할 때 사용
전달받은 데이터는 자식 컴포넌트에서 수정 불가능함
Props는 객체 형태로 전달되며, 컴포넌트에 사용된 모든 속성들은 하나의 props 객체로 모아짐
예제
// 부모 컴포넌트
<Child name="James" age={25} />
// 자식 컴포넌트에서는 하나의 props 객체로 받음
function Child(props) {
console.log(props); // { name: "James", age: 25 }
return <div>{props.name}</div>;
}
Props의 기본 문법
<Component 속성={값} />
부모 컴포넌트에서 데이터 전달
// App.tsx
import Child from "./components/Child";
export default function App() {
return (
<>
<h1>App</h1>
{/* props 객체로 전달 */}
<Child
name="James"
age={10}
foods={["apple", "banana"]}
address={{ zipcode: 1112, city: "Seoul" }}
/>
</>
);
}
자식 컴포넌트에서 Props 수신
Props를 받을 때 매개변수명으로 'props'를 사용하는 것이 React에서의 일반적인 관례
// Child.tsx
export default function Child(props: { //부모 컴포넌트로부터 전달된 props를 받음
name: string;
age: number;
foods: string[];
address: { zipcode: number; city: string };
}) {
return (
<div>
<h1>{props.name}</h1>
<h1>{props.age}</h1>
<h1>{props.foods[0]}</h1>
<h1>{props.address.city}</h1>
</div>
);
}
더 복잡한 프로젝트에서는 Interface를 사용하여 Props를 정의함
💡 ChildPropsType은 컴포넌트의 props 타입을 정의할 때 일반적으로 사용되는 규칙
// Child.tsx
interface ChildPropsType {
name: string;
age: number;
foods: string[];
address: { zipcode: number; city: string };
}
export default function Child(props: ChildPropsType) {
return (
<div>
<h1>{props.name}</h1>
<h1>{props.age}</h1>
<h1>{props.foods[0]}</h1>
<h1>{props.address.city}</h1>
</div>
);
}
큰 프로젝트에서 Props 타입을 별도 파일로 분리하여 관리하면 효율적
여러 컴포넌트의 타입을 한 곳에서 관리 가능
타입 정의 파일(.d.ts) 특징:
💡
props.d.ts파일은 import 없이 전역에서 사용 가능
// src/types/props.d.ts
export interface ChildPropsType {
name: string;
age: number;
}
// Child.tsx
import { ChildPropsType } from './types';
export default function Child({ name, age }: ChildPropsType) {
// ...
}
Props 객체를 구조 분해하여 코드를 간결하게 작성 가능함
💡 객체는 JSX 표현식에서 직접 출력할 수 없음 ⇒
JSON.stringify()를 사용하여 문자열로 변환
export default function Child({ name, age, foods, address }: ChildPropsType) {
return (
<div>
<h1>{name}</h1>
<h1>{age}</h1>
<h1>{foods[0]}</h1>
<h1>{JSON.stringify(address)}</h1>
</div>
);
}
혹은 함수 내부에서 타입 지정과 함께 구조분해할당을 할 수도 있음
export default function Child(props: ChildPropsType) {
const {
name,
age,
foods,
address: { zipcode, city },
} = props;
return (
<div className="text-3xl font-bold">
<h1>{name}</h1>
<h1>{age}</h1>
<h1>{foods[0]}</h1>
<h1>{foods[1]}</h1>
<h1>{zipcode}</h1>
<h1>{city}</h1>
</div>
);
}
Props에 기본값 지정 가능. age 값 미전달 시 기본값 30 설정됨
export default function Child({ name, age = 30 }: { name: string; age?: number }) {
return (
<div>
<h1>{name}</h1>
<h1>{age}</h1>
</div>
);
}
Children은 컴포넌트 태그 사이의 내용을 자식 컴포넌트에 전달할 때 사용
컴포넌트당 하나만 존재하며, 컴포넌트 태그 사이에 위치한 모든 JSX 요소를 포함
Children은 children이라는 고정된 키값을 사용
// App.tsx
export default function App() {
return (
<>
<h1>App</h1>
<Child>
<h2>이것이 Children입니다</h2>
</Child>
</>
);
}
// Child.tsx
export default function Child({ children }: { children: React.ReactNode }) {
return <div>{children}</div>;
}
ReactNode는 더 넓은 범위를 커버하므로 Children의 타입으로 주로 사용
| 특징 | Props | Children |
|---|---|---|
| 전달 방식 | 부모 → 자식 | 태그 사이에 JSX로 전달 |
| 사용 목적 | 단순 데이터 전달 | 마크업 구조 전달 |
| 유연성 | 제한적 | 더 복잡한 구조 전달 가능 |
예제
<Child content="<h1>Hello</h1>" />
<Child>
<h1>Hello</h1>
</Child>
출처: 수코딩