수정에 대응하는 컴포넌트
대부분의 개발자들은 이미지와 같은 경우를 경험해 본 적이 있을 거라 생각한다. 웹 개발을 하다 보면 예 수정사항이 생기기 마련이다. 텍스트 추가나 색상 수정 같은 간단한 요구사항들은 생각보다 자주 일어나기도 한다.(우리 회사만 그럴지도..)
코드를 수정하려고 보면, 너무 사소한 수정조차 어려운 경우가 있다. 사용하고 견고하게 만들었다고 생각한 컴포넌트가 오히려 수정을 불가능하게 만들어 버린다. 단순히 빨간 텍스트를 추가하는 것 뿐인데도 말이다.
이번 글에서는 이전에 만들었던 공통 컴포넌트를 되돌아보며, 수정 사항에 어떻게 대응할 수 있었는지, 살펴보려고 합니다.
완벽한 재사용 컴포넌트!
프로젝트를 시작할 때 먼저 공통으로 사용할 수 있는 컴포넌트를 구현했다. ‘반복되는 작업을 미리 작성해 놓으면 생산성이 올라간다는 당연한 믿음’으로 코드를 작성했다.
공통 컴포넌트를 잘 만들어 놓으면 두 가지 장점을 가진다.
재사용성과 생산성이 높아진다.
유지 보수에 용이하다.
여기서 ‘잘’ 만들어야 한다는 것을 집중해야 한다.
기존 컴포넌트의 한계
처음에 작성한 Select
컴포넌트를 보자. options
, defaultValue
를 props
로 넘기기만 하면 셀렉트가 완성된다. Modal
도 몇 가지 props
만 넘기면 뚝딱! 만들어진다. 너무나 사용하기 편한 컴포넌트가 완성되었다!
// Select.tsx
<Select options={options} defaultValue={value} />
// Modal.tsx
<Modal
title={title}
description={description}
onConfirmButtonClick={...}
onCancelButtonClick={...}
/>
하지만 컴포넌트의 형태부터 기능까지 모든 상황에서 동일하게 사용할 수 있을 것이라는 착각 속에서 만들어진 컴포넌트는 실제 수정 작업에 있어 한계를 드러낸다.
가격을 선택하는 Select
가 있다. 그런데 여기에 빨간색으로 할인률을 표시해줘야 한다면 어떻게 할 것인가? 아니면 이미지가 달라야 한다면?
예를 들어, 단순히 텍스트를 추가하거나 할인율을 표시하는 것 같은 간단한 수정이 필요할 때마다 결국 새로운 컴포넌트를 만들어야 했다. 기존의 컴포넌트 구조가 확장 가능한 설계가 되어 있지 않았기 때문이다.
유연한 컴포넌트 만들기
저번 글에서 어떻게 공통 컴포넌트를 만들었는지 설명했지만 이번에는 수정사항과 함께 어떻게 변경했는지 보려고한다.
위에서 말한 초기의 공통 컴포넌트들은 정해진 기능 이외에 추가를 할 수 없는 구조다. 완벽하게 컴포넌트를 공통화 할 수 있다는 착각 속에서 만들어졌다. 그래서 나는 컴포넌트의 정의된 기능만 남겨놓은 headless와 필요한 구조로 만들 수 있도록 compound component를 만들었다
const ProductSelect = ({ products }) => {
...
return (
<Select>
<SelectTrigger>
선택없음
<img ... />
</SelectTrigger>
<SelectGroup>
{products.map(product) => {
return (
<SelectOption onClick={...}>
<p>{prouduct.name} <span>{product.discount}</span></p>
</SelctOption>
)
}}
</SelectGroup>
</Select>
)
}
처음 만든 컴포넌트 보다 형태에서 자유로움이 보인다. Select 가 가질 수 있는 역할에 따라 자식 컴포넌트들을 구성했고 기획에 따라 원하는 내용을 보여줄 수 있다.
Select의 기능은 useContext를 이용해 만들었으며, 이전 글에서 기능을 만드는 것을 보여줫으니 이번에는 넘어간다.
<Modal>
<ModalTitle></ModalTitle>
<ModalContent>
...
</ModalContent>
<ModalButtonGroup>
<CancelButton />
<ConfirmButton />
</ModalButtonGroup>
</Modal>
차이점
기존에 구현된 컴포넌트는 단순히 텍스트로만 이루어진 select라고 했을 때 너무 편하게 사용할 수 있었다. 그러나 단순한 텍스트 하나 추가하는 것도 힘들었다. 넣을 수는 있지만 점점 하나의 파일에 코드가 길어 지도록 구성되었다.
변경된 컴포넌트는 기획과 기능에 맞춰서 변경될 수 있으며 정해진 기본 기능은 해치치 않도록 구현되어있다. 어떤 이벤트에 맞춰 모달이 나타나고 바깥영역이나 닫기 버튼 클릭시 닫히는 등 기본 기능은 지키되 정의된 기능들을 추가하거나 수정할 수 있다.
정리하기
사실 처음에 공통 컴포넌트는 똑같은 것을 작성하고 싶지 않다는 이유에서 만들었다. 그러나 UI나 이벤트가 추가될 때마다 props로 받아서 코드를 작성해야 했다. 하나의 컴포넌트가 너무 많은 역할을 담당하고 있다는 것을 느꼈다.
따라서, 컴포넌트의 역할을 분리하고 형태에 따라 쉽게 변경될 수 있도록 Compound 패턴으로 작성했다.