compound 사전적 의미
- 복합체
- 혼합물, 화합물
- 형) 합성의
리액트 컴포넌트 패턴에서의 Compound Component Pattern은 하나의 복합적인 컴포넌트를 특정 기능을 가지는 서브 컴포넌트들로 분리하고 사용하는 입장에서 원하는 형태로 서브 컴포넌트를 조립하여 컴포넌트를 구성하는 디자인 패턴을 의미합니다.
해당 패턴을 이해하기 쉬운 예제가 바로 select와 option입니다.
// example <label for="pet-select">Choose a pet:</label> <select name="pets" id="pet-select"> <option value="">--Please choose an option--</option> <option value="dog">Dog</option> <option value="cat">Cat</option> <option value="hamster">Hamster</option> </select>
function CompoundComponentMain() {
return <div>{children}</div>;
}
const CompoundComponet = Object.assign(CompoundComponentMain, {
// 서브 컴포넌트 입력
// 아래는 예시입니다.
Sub1: SubComponent1,
Sub2: SubComponent2,
Sub3: SubComponent3,
...
});
export default CompoundComponent;
function App() {
return (
<CompoundComponent>
<CompoundComponent.Sub1 />
<CompoundComponent.Sub2 />
<CompoundComponent.Sub3 />
</CompoundComponent>
);
}
부모 컴포넌트는 다음과 같이 작성했습니다.
function SearchResultSectionMain({ children, style }: Props) {
return <Section className={style}>{children}</Section>;
}
const ResultSection = Object.assign(SearchResultSectionMain, {
Title: SearchResultTitleOnly,
TitleWithMove: SearchResultTitleWithMove,
List: SearchResultList,
Item: SearchResultItem,
LinkItem: SearchResultLinkItem,
});
export default ResultSection;
Title과 Item은 이동 여부에 따라 컴포넌트가 2가지로 나뉘기 때문에 서브 컴포넌트가 각각 2개씩 존재합니다.
List에서는 검색 결과가 없는 경우 EmptySearch
컴포넌트를 보여주도록 했습니다.
이전 코드와 비교했을 때
기존의 검색 페이지를 Compound Component를 활용해서 리팩토링을 진행하였습니다.
해당 컴포넌트는 데이터를 Map을 사용해서 LinkItem
에 각 item 데이터를 전달해야했는데 이 때문에 진행하면서 막히는 부분이 많았습니다.
처음에는 서브 컴포넌트인 List
안에서 데이터를 순회해서 child인 Item
에 보내주려고 했는데 받아오는 데이터에 따라 한번 더 속성에 접근해야하는 경우가 생겼고, 이를 해결하기위해 type을 보내주고 type에 따라 처리하는 방식을 고민했지만 코드가 복잡해져 이 부분은 더 진행하지 않았습니다.
결과적으로 위의 이미지와 같이 처리하였습니다.
복잡한 UI 구성 : UI가 복잡하고 다양한 기능을 포함하는 경우, 이를 각각의 작은 조각으로 나누어 구성할 수 있습니다. 각 조각은 하위 컴포넌트로 만들어지고, 이러한 하위 컴포넌트를 조합하여 더 큰 컴파운드 컴포넌트를 생성할 수 있습니다.
재사용성이 필요한 경우 : 여러 곳에서 동일한 또는 유사한 기능을 사용해야 하는 경우, 이러한 기능을 하위 컴포넌트로 추상화하고 컴파운드 컴포넌트로 조합하여 재사용성을 높일 수 있습니다.
모듈성이 필요한 경우 : 기능을 독립적인 작은 컴포넌트로 나누어 개발하고 테스트해야 하는 경우, 컴파운드 컴포넌트 패턴을 사용하여 각 컴포넌트를 모듈화할 수 있습니다.
인터페이스 추상화가 필요한 경우 : 상위 컴포넌트에서 하위 컴포넌트의 구현 세부 사항을 숨기고 인터페이스를 제공해야 하는 경우, 컴파운드 컴포넌트 패턴을 사용하여 구현 세부 사항을 추상화할 수 있습니다.
유연한 UI 구성이 필요한 경우 : 다양한 UI 요구 사항에 대응하기 위해 조합 가능한 하위 컴포넌트를 사용하여 유연하고 확장 가능한 UI를 구성해야 하는 경우, 컴파운드 컴포넌트 패턴을 사용할 수 있습니다.
원티드 프리온보딩 챌린지에서 SOLID한 컴포넌트를 만들기 위한 방법 중 Compound Component를 소개한 적이 있었는데 직접 써보니까 왜 사용하는지 알 수 있었습니다.
참고
https://fe-developers.kakaoent.com/2022/220731-composition-component/
https://patterns-dev-kr.github.io/design-patterns/compound-pattern/