Compound Pattern을 사용해 재사용 극대화하기
합성 컴포넌트를 사용해 유연한 UI, 재사용성 향상, 가독성 높은 코드를 만들어보자. 👀
Compound Pattern이란
Compound Pattern은 여러개의 작은 컴포넌트들을 합성해 만든 디자인 패턴입니다. 여러 개의 작은 컴포넌트란 어떤 말일까요? HTML의 select
태그를 봐봅시다.
select 태그와 option 태그를 사용해 하나의 기능이 완성되는 것 처럼 요소들을 세분화하고 합성해서 사용하는 것을 말합니다. Compound Pattern은 UI 라이브러리(Radix UI, MUI)에서 많이 볼 수 있습니다. UI 라이브러리에서 이 패턴을 사용한다는 건 많은 이점이 있기 때문에 사용한다고 볼 수 있습니다.
Compound Pattern을 사용하면 어떤 이점이 있는지 알아보겠습니다
Compound Pattern의 장점
- 유연한 UI 구조
- 가독성 및 일관성 있는 코드
- props 관리
- prop drilling
- 관심사 분리
Compound Pattern을 사용하면 장점은 크게 4가지로 구분됩니다. 우선 코드 예시를 봐보겠습니다. 다음은 제가 실제로 작업하면서 만들었던 코드입니다.
저는 각 Form에 해당하는 Field들을 Compound Pattern을 적용 했습니다. 먼저 왜 유연한 UI 구조인지에 대해 알아볼게요.
왜 유연한 UI 구조인가?
위 코드를 보시면 Atomic Pattern처럼 여러 개의 작은 컴포넌트들을 조합해 사용하고 있습니다. 즉 아래와 같이 하나의 컴포넌트가 여러 가지의 일들을 내장하고 있는 게 아니라 조합해서 사용하기 때문에 유연하다는 특징이 있습니다.
조금 더 설명하자면 아래 예시는 컴포넌트 이름이 잘못되었을 수 있지만, 어떠한 이름을 지어도 저 컴포넌트 안에 어떠한 요소들이 있는지 파악하기 힘들거나 이름부터 하는일이 많아진다고 느껴 거부감이 들게됩니다. 만약 새로운 요구사항이 들어와 Label
이 없는 FormField를 만든다면 어떻게 해야할까요 ??? 아마 Compound Pattern을 사용하지 않는다면 새로운 컴포넌트를 만들거나 또는 props로 전달해 내부 로직에 추가가 될거에요.
props 관리
요구사항에 맞춰 작업하기 위해 props를 추가적으로 전달하게 된다면 props는 끝날 줄 모르게 늘어나게 됩니다. 즉 컴포넌트의 props가 3개를 초과하게 됩니다. 다음은 제가 협업하면서 팀원이 작성했던 코드를 가져와 볼게요.
위에 Compound Pattern을 사용할 때를 비교해보시면 어떤 느낌이 드시나요? "이건 좀 아니지 않나" 또는 "나쁘지 않은데?" 라는 생각이 들 수 있지만, 이 컴포넌트를 사용하는 팀원 입장에서도 생각해보면 좋을 것 같습니다. 본인이 혼자 만들고 사용하는 건 전혀 문제가 되지 않습니다. 처음부터 만들었으니까요. 하지만 사용하는 팀원들은 이해하는데 시간을 꽤 투자할 거에요.
실제로 협업할 때 저희 팀원은 Label이 없는 상황일 때 새로운 컴포넌트를 만들었습니다. 결국 재사용성 부분도 문제가 있습니다. 컴포넌트도 마찬가지로 전달해야하는 props를 웬만하면 3개를 초과하지 않는게 사용하는 개발자 입장에서 더 좋을 것 같습니다. 사소하지만 이러한 DX들이 중요하다는 생각이 듭니다.
prop drilling
Compound Pattern은 Context API를 사용하기 때문에 부모 컴포넌트에서 자식 컴포넌트로 전달할 때 직접 전달할 수 있다는 장점이 있습니다. 따라서 Props Drilling에 대한 걱정이 없고 작은 단위로 Context API를 사용하기 때문에 리 렌더링 문제도 크게 걱정하지 않아도 됩니다.
가독성 및 일관성 있는 코드
가독성이 높을 수밖에 없는 이유는 여러 가지의 요소들로 구성되어있기 때문입니다. 추가적으로 이름의 통일성이 있어 가독성이 높아진 것도 한몫합니다. 추가 요구사항에도 대응할 수 있기 때문에 재사용성도 높아지니 일관성 있는 코드라고도 부를 수 있을 것 같네요.
관심사 분리
핵심적인 로직은 부모 컴포넌트가 담당하고 있습니다. 따라서 자식 컴포넌트들은 본연의 역할만 수행하게 됩니다. Atomic Pattern처럼 컴포넌트들을 세분화했기 때문에 수정해야 할 요소를 쉽게 파악할 수 있고 컴포넌트 내부만 보아도 간단하여서 파악하거나 수정할 때 유리합니다. 즉 재사용성을 높이는 방법이라고 볼 수 있습니다.
Compound Pattern의 단점
단점으로는 JSX 코드가 많이 길어지는 부분과 레이아웃 순서대로 배치되기 때문에 간혹 이상하게 나오는 경우도 있습니다. 너무 좋은 장점 때문에 일어난 단점이기에 팀원들과 상의하면 충분히 해결할 수 있는 문제라고 봅니다.
Compound Pattern 구현해보기
정말 간단한 형태인 카운트를 예제로 Context API를 사용해 만들어보겠습니다. 항상 무엇인가를 만들 때 필요한 요소가 무엇인지를 알아야 하고, 상태를 어떻게 관리할 건지에 대해서도 고민해보면 좋을 것 같습니다.
- 카운트된 숫자를 보여줄 컴포넌트
- +1 증가하는 버튼 컴포넌트
- -1 감소하는 버튼 컴포넌트
구현부
사용부
마치며
상태가 부모 컴포넌트에서만 관리된다면 로직을 부모 컴포넌트(Count)에서 관리해도 상관없습니다. 만약 부모 컴포넌트에서 로직을 관리한다면 props 전달은 필요 없겠네요. 이러한 부분에서 Popover
와 같은 컴포넌트에서 매우 유용할 것 같습니다.
저는 부모 컴포넌트에서 로직을 지정하지 않고 사용하는 측 컴포넌트에서 작성해 전달해주도록 했습니다. 컴포넌트 만들 때 재사용성을 고려한다면 이처럼 Compound Pattern을 적극 사용해보는 걸 추천합니다.