[React] 리액트 Props, Children

윤지·2024년 11월 28일

React

목록 보기
8/15
post-thumbnail

리액트는 부모에서 → 자식 컴포넌트에게만 데이터를 전달할 수 있음 ⇒ 단방향 데이터 흐름

💡 반면 Vue는 양방향 데이터 바인딩을 지원


Props: 부모 → 자식 데이터 전달

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 속성={} />

Props 예제

부모 컴포넌트에서 데이터 전달

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

Props를 Interface로 관리하기

더 복잡한 프로젝트에서는 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 타입 파일 분리하기

큰 프로젝트에서 Props 타입을 별도 파일로 분리하여 관리하면 효율적

여러 컴포넌트의 타입을 한 곳에서 관리 가능

타입 정의 파일(.d.ts) 특징:

  • TypeScript의 전역 타입 정의 파일
  • 타입 정보만 제공 (JavaScript 변환 X)
  • src 폴더에서 자동 인식

💡 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 객체를 구조 분해 할당하기

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의 기본값 설정

Props에 기본값 지정 가능. age 값 미전달 시 기본값 30 설정됨

export default function Child({ name, age = 30 }: { name: string; age?: number }) {
  return (
    <div>
      <h1>{name}</h1>
      <h1>{age}</h1>
    </div>
  );
}

Children: 태그 사이 내용 전달

Children은 컴포넌트 태그 사이의 내용을 자식 컴포넌트에 전달할 때 사용

컴포넌트당 하나만 존재하며, 컴포넌트 태그 사이에 위치한 모든 JSX 요소를 포함

Children은 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와 ReactElement

  • ReactNode: 모든 React 요소를 포함하는 타입 (string, number, JSX, null 등)
  • ReactElement: JSX 요소만 포함하는 타입

ReactNode는 더 넓은 범위를 커버하므로 Children의 타입으로 주로 사용


Props vs Children의 차이점

특징PropsChildren
전달 방식부모 → 자식태그 사이에 JSX로 전달
사용 목적단순 데이터 전달마크업 구조 전달
유연성제한적더 복잡한 구조 전달 가능

예제

Props로 데이터 전달

<Child content="<h1>Hello</h1>" />
  • 문자열로 전달되어 JSX 구조로 인식되지 않음

Children으로 데이터 전달

<Child>
  <h1>Hello</h1>
</Child>
  • JSX 구조 그대로 전달됨

출처: 수코딩

profile
프론트엔드 공부 기록 아카이빙🍁

0개의 댓글