본문 바로가기
📌 Front End/└ React

[React] 리액트 Children Props(props.children 사용)

by 쫄리_ 2024. 9. 3.
728x90
반응형

📌 Children Props

리액트 모든 컴포넌트에서 children props를 사용할 수 있습니다.
children props란 컴포넌트의 여는 태그와 닫는 태그 사이의 내용입니다.

 

사용예시

이 태그에서 Hello world! 문자열이 

Welcome 컴포넌트의 children props로 전달이 되어 접근할 수 있습니다.

function App() {
  return <Welcome>Hello world!</Welcome>
}
function Welcome(props) {
  return <p>{props.children}</p>;
}

📌 합성(Composition)과 props.children

🔎 children 이란?

props.children은 React 컴포넌트의 특별한 props입니다.

컴포넌트가 다른 컴포넌트를 포함할 때, 그 안에 들어가는 내용을 모두 children으로 접근할 수 있어요.

 

App 컴포넌트에서 작성한 <Category> ~ </Category> 내부에 작성한 내용들이
 Category 컴포넌트에게 props.children으로 전달됩니다.
 
{props.children}은 <Category> ~ </Category> 내부에 
작성된 내용들을 화면에 표시합니다.


 

예를 들어 <Category>라는 컴포넌트를 만들었다고 생각해봅시다.

<Category> 태그 사이에 들어가는 내용은 모두 props.children으로 전달됩니다.

위 코드에서 <Category> 태그 안에 있는 <li> 태그들이 props.children으로 전달되고,

Category 컴포넌트는 이를 <ul> 태그로 감싸서 화면에 표시합니다.

const Category = (props) => {
  return <ul>{props.children}</ul>;
};

const App = () => (
  <Category>
    <li>First item.</li>
    <li>Second item.</li>
    <li>Another item.</li>
  </Category>
);

 


📌 props.children 필요성

props.children은 자식 엘리먼트나 컴포넌트가 미리 몇 개가 들어올지 알 수 없거나,

다양한 상황에서 재사용 가능하게 만들 때 유용합니다.

이렇게 하면 코드가 더 간단하고 재사용 가능해집니다.

const li_Array = ["First item.", "Second item."];

const Category = (props) => {
  return <ul>{props.children}</ul>;
};

const App = () => (
  <Category>
    {li_Array.map((value, idx) => (
      <li key={idx}>{value}</li>
    ))}
  </Category>
);

📌 props.children 메서드

React는 props.children가 컴포넌트 내의 JSX 요소를 단순히 화면에 표시하는 기능 이외에도 

다양하게 다룰 수 있는 메서드를 제공합니다.

 

React.Children 전용 메서드는 아니지만, 

props.children을 복제하여 변경이 필요한 경우 React.cloneElement 메서드를 사용할 수 있습니다.
 
props.children은 수정이 불가능한 읽기 전용이므로 

React.cloneElement 메서드를 사용하여 props.children을 복제 후 수정할 수 있습니다.

메서드 설명
React.Children.map 각 자식에 대하여
함수를 호출하고, 새 배열을 반환
React.Children.forEach 각 자식에 대하여 함수를 호출
React.Children.count 자식의 수를 반환
React.Children.only 자식이 하나만 있는지 확인
React.Children.toArray 자식을 새 배열로 반환

📌 자식과 자손

React에서 props.children을 사용할 때 주의할 점은 모든 요소들이 자식(child)으로 취급되지 않는다.

props.children은 직접적인 첫 번째 자식만을 가리킵니다.

  • 자식 (Child) : 컴포넌트가 직접 감싸고 있는 요소들입니다.
  • 자손 (Descendant) : 자식 요소의 내부에 중첩되어 있는 요소들까지 포함하는 더 넓은 범위의 요소들

 

위 코드에서 Category의 직접적인 자식은 <ul> 엘리먼트입니다.

<ul> 안에 있는 <li> 엘리먼트들은 Category 입장에서는 "자손(descendant)"이지, 직접적인 자식은 아닙니다.

그래서 React.Children.count로 Category의 자식 개수를 확인하면 1개만 출력됩니다.

const App = () => (
  <Category>
    <ul>
      {li_Array.map((value, idx) => (
        <li key={idx}>{value}</li>
      ))}
    </ul>
  </Category>
);
class Category extends React.Component {
  render() {
    console.log("자식의 수 : " + React.Children.count(this.props.children));
    return <React.Fragment>{this.props.children}</React.Fragment>;
  }
}


📌 Children Props Type

타입스크립트에서는 Children Props를 전달을 할 때 타입을 지정을 해주어야 합니다.
그렇다면 어떤 타입으로 지정을 해주어야 하는지 알아보겠습니다.

대부분의 경우, React.ReactNode를 사용하면 대부분의 시나리오에 적합하고 유연하게 대응할 수 있어요.

따라서 children props의 타입을 지정할 때는 React.ReactNode를 사용하는 것이 좋습니다.

 

  • JSX.Element : 단일 React 요소만 허용. 예외 사항이 많음
  • React.ReactChild : 문자열, 숫자 등을 포함하지만 배열은 허용되지 않으며 사용이 지양됨
  • React.PropsWithChildren : children이 선택 사항인 경우 적합
  • React.ReactNode : 모든 타입을 지원하며 가장 유연하고 많이 사용됨

🔎 JSX.Element

JSX.Element는 하나의 React 요소만을 나타낼 수 있습니다.

문자열, 숫자와 같은 원시 타입은 사용할 수 없습니다.

import React from "react";

type OnlyElementProps = {
  children: JSX.Element; // 단일 React 요소만 허용
};

const OnlyElementComponent: React.FC<OnlyElementProps> = ({ children }) => {
  return <div>{children}</div>;
};

// ⭕사용 예시 - 올바른 사용
const App = () => (
  <OnlyElementComponent>
    <h1>이것은 React 요소입니다</h1>
  </OnlyElementComponent>
);

// ❌사용 예시 - 잘못된 사용 (에러 발생)
// <OnlyElementComponent>
//   Hello World!
// </OnlyElementComponent>

🔎 React.ReactChild

React.ReactChild는 JSX.Element, string, number를 포함하는 타입입니다.

배열은 허용되지 않으며, React 18부터는 사용이 지양됩니다.

import React from "react";

type ChildProps = {
  children: React.ReactChild; // React 요소, 문자열, 숫자 등 허용
};

const ChildComponent: React.FC<ChildProps> = ({ children }) => {
  return <div>{children}</div>;
};

// ⭕사용 예시 - 올바른 사용
const App = () => (
  <>
    <ChildComponent>텍스트도 가능합니다</ChildComponent>
    <ChildComponent>{42}</ChildComponent>
  </>
);

// ❌사용 예시 - 잘못된 사용 (에러 발생, 배열은 허용되지 않음)
// <ChildComponent>
//   {["배열", "은", "허용되지 않습니다."]}
// </ChildComponent>

🔎 React.PropsWithChildren

React.PropsWithChildren은 children이 옵션인 경우에 사용하는 타입입니다.

children이 필수일 때는 부적합합니다.

type PropsWithChildren<P = unknown> = P & {
  children?: ReactNode | undefined;
}
import React from "react";

type OptionalChildrenProps = React.PropsWithChildren<{
  title: string;
}>;

const OptionalChildrenComponent: React.FC<OptionalChildrenProps> = ({
  title,
  children,
}) => {
  return (
    <div>
      <h1>{title}</h1>
      {children && <div>{children}</div>}
    </div>
  );
};

// 사용 예시 - children이 없어도 작동
const App = () => (
  <>
    <OptionalChildrenComponent title="제목만 있는 컴포넌트" />
    <OptionalChildrenComponent title="제목과 내용이 있는 컴포넌트">
      <p>내용</p>
    </OptionalChildrenComponent>
  </>
);

🔎 React.ReactNode

React.ReactNode는 가장 범용적이고 많이 사용되는 타입입니다.

모든 React 컴포넌트에서 children을 처리하기 위해 이 타입을 사용할 수 있어요.

거의 모든 타입의 값을 허용하기 때문에 children props의 타입을 지정할 때 가장 안전하고 널리 사용됩니다.

  • 문자열 (string), 숫자 (number), 불리언 (boolean)
  • null과 undefined
  • JSX.Element, React Fragments 등 대부분의 React 요소들
import React from "react";

type FlexibleProps = {
  children: React.ReactNode; // 거의 모든 타입 허용
};

const FlexibleComponent: React.FC<FlexibleProps> = ({ children }) => {
  return <div>{children}</div>;
};

// 사용 예시 - 모든 타입이 허용됨
const App = () => (
  <>
    <FlexibleComponent>텍스트도 되고</FlexibleComponent>
    <FlexibleComponent>{42}</FlexibleComponent>
    <FlexibleComponent>
      <h1>React 요소도 됩니다</h1>
    </FlexibleComponent>
    <FlexibleComponent>
      <>
        <p>Fragment도 됩니다</p>
        <p>여러 요소도 가능합니다</p>
      </>
    </FlexibleComponent>
  </>
);

 


728x90
반응형