React/React 문법

[React]props.children 사용

DevStory 2021. 10. 6.

이번 포스팅에서 컴포넌트 간 합성(Composition)과 props.children을 소개합니다.

 


합성(Composition)과 props.children

children이란?

공식 문서에는 props.children에 대해 아래와 같이 설명하고 있습니다.

어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올지 미리 예상할 수 없는 경우가 있습니다. 범용적인 ‘박스’ 역할을 하는 Sidebar 혹은 Dialog와 같은 컴포넌트에서 특히 자주 볼 수 있습니다.

 

저는 공식 문서에서 설명하고 있는 내용이 이해가 되지 않아서 props.children을 다음과 같이 해석하고 이해합니다.

태그와 태그 사이의 모든 내용을 표시하기 위해 사용되는 특수한 props

 

예제 코드

다음은 생명주기 및 데이터를 변경하지 않고 props.children을 화면에 표시하는 간단한 컴포넌트입니다.

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

children은 특수한 속성이므로 아래와 같이 작성할 수도 있습니다.

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

 

다음은 위에서 작성한 Category 컴포넌트를 사용하는 App 컴포넌트입니다.

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

 실행 결과

 

동작 과정

App 컴포넌트에서 작성한 <Category> ~ </Category> 내부에 작성한 내용들이 Category 컴포넌트에게 props.children으로 전달됩니다.

 

{props.children}은 <Category> ~ </Category> 내부에 작성된 내용들을 화면에 표시합니다.


props.children 필요성

props.children은 주로 자식 컴포넌트 또는 html 엘리먼트가 어떻게 구성되어있는지 모르는데, 화면에 표시해야 하는 경우 사용합니다.

 

예를 들어서 <Category> ~ </Category> 안에 <li> 태그가 몇 개 작성될지 모릅니다.

const App = () => (
  <Category>
    {/* li 태그가 0개일 수도 있고 여러 개일 수도 있습니다.}
    <li>First item.</li>
    <li>Second item.</li>
    <li>Another item.</li>
  </Category>
);

 

props.children을 사용하지 않고 <Category> ~ </Category> 내부에 작성된 코드를 props을 통해 전달해야 하는 경우 다음과 같이 코드를 작성할 수 있습니다.

const App = () => (
  <Category body={
    <React.Fragment>
      <li>First item.</li>
      <li>Second item.</li>
      <li>Another item.</li>
    </React.Fragment>
    }
  />
);

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

위 방식은 몇 가지 문제가 있습니다.

첫째, props의 속성 이름을 무엇으로 할 것인지?

둘째, 여러 엘리먼트를 전달해야 하는 경우 <React.Fragment>로 감싸거나 <div>로 감싸야합니다.

셋째, <li> 태그를 동적으로 처리해야하는 경우가 존재할 수 있습니다.

 

하지만, props.children을 사용한다면, 위 문제에 대해 크게 생각할 필요가 없습니다.

// 3. 동적인 데이터라도 {props.children}을 사용하여 화면에 표시합니다.
const li_Array = ["First item.", "Second item."];

// 1. props 속성의 이름을 고민할 필요가 없습니다.
const Category = (props) => {
  return <ul>{props.children}</ul>;
};

// 2. <React.Fragment>를 사용하지 않아도 됩니다.
const App = () => (
  <Category>
    {li_Array.map((value, idx) => (
      <li key={idx}>{value}</li>
    ))}
  </Category>
);

이렇게 props.children을 사용하면, 코드의 재사용성을 향상하며 JSX 요소를 좀 더 유연하고 밀접하게 다룰 수 있습니다.


props.children 메서드

React는 props.children가 컴포넌트 내의 JSX 요소를 단순히 화면에 표시하는 기능 이외에도 다양하게 다룰 수 있는 메서드를 제공합니다.

메서드 설명
React.Children.map 각 자식에 대하여 함수를 호출하고, 새 배열을 반환합니다.
React.Children.forEach 각 자식에 대하여 함수를 호출합니다.
React.Children.count 자식의 수를 반환합니다.
React.Children.only 자식이 하나만 있는지 확인해야 하는 경우 사용합니다.
React.Children.toArray 자식을 요소로 가지는 새 배열로 반환합니다.

React.Children 전용 메서드는 아니지만, props.children을 복제하여 변경이 필요한 경우 React.cloneElement 메서드를 사용할 수 있습니다.

 

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

 

메서드 사용 방법은 세부적으로 알아볼 계획이라서 따로 포스팅할 예정입니다.


자식과 자손

props.children 사용시 주의할 사항으로는 태그와 태그 사이의 모든 요소들을 자식 취급하지는 않습니다.

 

아래 코드에서 Category 컴포넌트의 자식 요소는 <ul> 엘리먼트입니다.

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

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

<ul> ~ </ul> 사이에 있는 <li> 엘리먼트는 <Category> 기준으로는 자손이며, <ul> 기준으로는 자식 엘리먼트입니다.

 

React에서 자식의 개수를 반환하는 React.Children.count 함수를 사용하여 Category 컴포넌트의 자식의 개수를 확인해보면, 1개만 출력되는 것을 확인할 수 있습니다.

class Category extends React.Component {
  render() {
    console.log("자식의 수 : " + React.Children.count(this.props.children));
    return <React.Fragment>{this.props.children}</React.Fragment>;
  }
}

실행 결과

 

반응형

댓글