본문으로 바로가기

[React] 컴포넌트 합성이란?

category 1. 웹개발/1_1_5 React JS 2024. 7. 6. 11:49

 

 

모던 웹 개발에서 컴포넌트 기반 아키텍처는 빠르게 표준이 되었습니다. 특히 React와 같은 라이브러리를 사용하면 UI를 작은, 재사용 가능한 컴포넌트로 분리하여 개발하는 것이 일반적입니다. 하지만 이 과정에서 단순히 컴포넌트를 나누는 것만으로는 부족합니다. 여기서 중요한 개념이 바로 컴포넌트 합성입니다.

 

컴포넌트 합성은 여러 개의 작은 컴포넌트를 조합하여 더 큰 기능을 수행하는 컴포넌트를 만드는 방법을 의미합니다. 이 접근 방식은 코드의 재사용성을 높이고, 유지보수를 쉽게 하며, 복잡한 UI를 관리하는 데 매우 유용합니다. 따라서 컴포넌트 합성은 단순히 좋은 습관이 아니라, 효율적이고 확장 가능한 애플리케이션을 개발하는 데 필수적인 기술입니다.

 

이번 글에서는 컴포넌트 합성이 왜 중요한지, 어떻게 적용할 수 있는지, 그리고 이를 통해 얻을 수 있는 다양한 이점에 대해 살펴보겠습니다.

 

컴포넌트 합성?

쉽게 말하자면, "컴포넌트에서 다른 컴포넌트를 담기" 라고 보시면 됩니다.

const Parent = ({ children }) => (
	<div>{children}</div>
)

const App = () => {
	<Parent>
		<Child/>
	</Parent>
}

 

위의 코드처럼 부모 컴포넌트에서는 children이라는 특수 props를 사용해서 자식 컴포넌트를 렌더링할 수 있습니다. 하지만, 꼭 children을 사용할 필요는 없고 아래와 같이도 사용이 가능합니다.

 

아래 코드와 같이 props를 통해서 컴포넌트를 주입하는 방식도 컴포넌트 합성이라고 말할 수 있습니다.

const SplitPane = (props) => (
  <section>
    <div>
      {props.left}
    </div>
    <div>
      {props.right}
    </div>
  </section>
)

const App = () => (
  <SplitPane
    left={
      <Contacts />
    }
    right={
      <SideMenu />
    }
  />
)

 

 

합성의 장점

1. 재사용성

React에서는 다음과 같이 말합니다.

“합성을 사용하여 컴포넌트 간에 코드를 재사용하는 것이 좋습니다.”

 

그렇다면 어떻게 재사용이 될까요?

만약 잘 만들어 놓은 버튼이 있다면, 사용부에서 컴포넌트를 주입함으로써 만들어놓은 컴포넌트를 재사용할 수 있습니다.

const Button = () => (
  <button>버튼</button>
)

const UI = () => (
  <Layout>
    <Button />
  </Layout>
)

 

2. SRP

SRP(Single Responsibility Principle)는 쉽게 말하면 관심사의 분리입니다.

컴포넌트 합성을 이용하면 SRP를 더욱 명확하게 달성할 수 있습니다.

 

아래 코드를 보시면 한 컴포넌트 내에서 데이터 패칭, 에러 핸들링 그리고 로딩에 대한 처리가 모두 한 번에 일어나고 있는 것을 확인할 수 있습니다.

const LegenedComponent = () => {
  const { data, isLoading, isError } = useFetch();
	
  if (isError) return <div>error...!</div>;
  if (isLoading) return <div>loading...!</div>;
	
  return <div>{data}</div>;
}

 

위의 코드가 안좋은 코드는 아니지만, 합성을 통해서 좀 더 개선을 하자면 좀 더 익숙한 형태인 아래와 같은 코드가 작성됩니다. 에러 바운더리와 서스펜스를 사용하였고, 대표적으로 합성을 통해서 관심사를 분리한 예시입니다.

const UI = () => (
  <ErrorBoundary fallback={<div>error...!</div>}>
    <Suspense fallback={<div>loading...!</div>}>
      <LegenedComponent />
    </Suspense>
  </ErrorBoundary>
)

 

위의 코드처럼 작성하면 에러에 대한 로직과 로딩에 대한 로직이 변경되어도 새롭게 추가한 LegenedComponent에는 아무런 영향이 일어나지 않습니다. 서로가 서로에 대해서 아무것도 알고 있지 않기 때문입니다.

 

 

 

References

https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html