1 분 소요

📄 리액트 공식 문서 Composition vs Inheritance


1. props.children

리액트 공식 문서에서는 props.children에 대해 다음과 같이 설명한다.

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


나는 props.children을 사용하는 것이, 컴포넌트에 구멍을 뚫어주는 것이라 해석했다. 어떤 자식 컴포넌트가 들어올지 알 수 없는 경우에 {props.children}으로 구멍을 뚫어 자리를 마련해두고, 그 자리에 임의의 자식 컴포넌트가 들어올 수 있도록 하는 것이다.


function FancyBorder(props) {
  return (
    <div className={"FancyBorder FancyBorder-" + props.color}>
      {props.children}
    </div>
  );
}


다음과 같이 다른 컴포넌트에서 props.children이라는 구멍에 JSX를 중첩해서 임의의 자식을 전달할 수 있다.

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      {/* 여기부터 */}
      <h1 className="Dialog-title">Welcome</h1>
      <p className="Dialog-message">Thank you for visiting our spacecraft!</p>
      {/* 여기까지 */}
    </FancyBorder>
  );
}


만약 컴포넌트에 두 개 이상의 구멍이 필요하다면, children 대신 자신만의 방식으로 적용해볼 수도 있다.

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">{props.left}</div>
      <div className="SplitPane-right">{props.right}</div>
    </div>
  );
}

function App() {
  return <SplitPane left={<Contacts />} right={<Chat />} />;
}

<Contacts /><Chat />같은 React 엘리먼트는 단지 (함수) 객체이기 때문에 다른 데이터처럼 prop으로 전달할 수 있다. React에서 prop으로 전달할 수 있는 것에는 제한이 없다.


따라서 태그를 동적으로 처리해야하는 경우에도 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>
);




3. props.children 사용해보기

레이아웃 컴포넌트를 만들어서 _app.tsx 혹은 _app.js에서 Component를 감싸주어 페이지가 변경되어도 모든 페이지에서 레이아웃이 공통적으로 보여지고, 레이아웃 컴포넌트 내부의 Component, 즉 props.children만 변경되도록 할 수 있다.


Layout 컴포넌트

export default function Layout(props: ILayoutProps) {
  return (
    <>
      <LayoutHeader />
      <LayoutBanner />
      <LayoutNavigation />
      <LayoutSidebar />
      <Body>{props.children}</Body>
      <LayoutFooter />
    </>
  );
}


App 컴포넌트

const App = ({ Component, pageProps }: AppProps) => {
  return (
    <RecoilRoot>
      <ApolloSetting>
        <Global styles={globalStyles} />
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </ApolloSetting>
    </RecoilRoot>
  );
};

export default App;

댓글남기기