'펀잇'에서 디자인 마이그레이션 작업을 진행하면서,
약간씩 다른 컴포넌트를 구현해야 할 일이 생겼다.
위 사진은 꿀조합에 대한 정보를 요약해서 보여주는 컴포넌트로
많은 페이지의 이곳저곳에서 사용되고 있다.
사실상 같은 정보를 내려받는 컴포넌트인데,
디자인이 4가지로 나누어져서
이를 모두 구현해야 할 필요가 생겼다.
예전에는 디자이너분들이 없기도 했고,
해봤자 2가지 정도의 시안으로 나누어졌기 때문에
그냥 페이지에 따라 조건문 처리를 해 구현했다.
하지만, 이제는 4가지나 되고,
조건문 처리를 해서 만들기에는 코드가 너무 더러워진다.
그렇다고 같은 정보를 받고 있는 컴포넌트를
굳이 4개를 나눠 만드는 건 시간과 인력 낭비이다.
그리고, 나중에 시안이 더 늘어나게 되면?
한, 두개쯤은 몰라도 40개, 100개씩 늘어나게 되면 감당할 수 없다.
그래서 compound component pattern을 활용해
레고 블록을 조립하듯 컴포넌트를 끼워 맞춰보기로 했다.
compound component pattern란
여러 컴포넌트를 모아 하나의 복합적인 컴포넌트를 만드는 디자인 패턴이다.
이 컴포넌트로 보면,
좋아요를 누를 수 있는 하트 버튼,
이미지,
제목,
작성자,
작성 날짜
이렇게 나눌 수 있는 것이다.
이렇게 조합 가능한 컴포넌트를 다 나누고,
이를 블록 맞추듯 하나하나 조립하면 된다.
먼저, 이 꿀조합 컴포넌트는 다양한 페이지에서 사용된다.
따라서, Context API를 사용해 컴포넌트가 상태를 공유할 수 있도록 한다.
import { createContext } from 'react';
import type { Recipe } from '@/types/recipe';
interface RecipeItemValue {
recipe: Recipe;
children?: React.ReactNode;
}
export const RecipeItemValueContext = createContext<RecipeItemValue | null>(null);
const RecipeItemProvider = ({ children, recipe }: RecipeItemValue) => {
const recipeItemValue = {
recipe,
children,
};
return <RecipeItemValueContext.Provider value={recipeItemValue}>{children}</RecipeItemValueContext.Provider>;
};
export default RecipeItemProvider;
그리고 해당 Provider를 꿀조합 컴포넌트에 감싸주어
상태를 공유할 수 있게 해 준다.
이제 children 부분에 원하는 컴포넌트를 넣어
새로운 컴포넌트를 만들어낼 수 있다.
const RecipeItem = ({ recipe, children }: RecipeItemProps) => {
const { id } = recipe;
return (
<RecipeItemProvider recipe={recipe}>
<Link to={`${PATH.RECIPE}/${id}`}>{children}</Link>
</RecipeItemProvider>
);
};
이제 초기 준비는 끝났다.
내가 조합하고 싶은 컴포넌트를 분리해서 구현해 보자.
const Title = () => {
const {
recipe: { title },
} = useRecipeItemValueContext();
return (
<Text className={ellipsis} size="caption1" weight="semiBold" color="default">
{title}
</Text>
);
};
context에서 받아온 정보를 바탕으로 각 컴포넌트를 구상한다.
다 구현했으면 이름에 맞춰 묶어준다.
이렇게 정의하면, 이 타이틀이 RecipeItem의 하위에 있는 Title임을 명확히 알 수 있다.
RecipeItem.Title = Title;
이제 <RecipeItem.Title> 형태로 어디서든 사용할 수 있다.
export const DefaultRecipeItem = ({ recipe }: RecipeItemProps) => {
return (
<RecipeItem recipe={recipe}>
<RecipeItem.ImageAndFavoriteButton />
<div style={{ height: '8px' }} />
<RecipeItem.Title />
<RecipeItem.AuthorAndCreatedDate />
</RecipeItem>
);
};
첫 번째, 꿀조합 컴포넌트를 이렇게 조립했다.
한 컴포넌트의 코드 길이가 짧고,
이름이 명시적으로 나와있기 때문에
확실히 알아보기가 편하다.
'아, 이 꿀조합 컴포넌트는 이미지와 좋아요 버튼이 있고,
타이틀이 있으며 작성자와 작성 일자를 가지고 있구나'를
코드만 보고서도 알 수 있게 되는 것이다.
이런 식으로 디자이너분들이 작업해 주신 Tob bar도
버전이 8개 정도 되었는데 한 개의 컴포넌트로 줄일 수 있었다.
compound component pattern이 완벽한 해결책일 수는 없다.
코드를 줄이기 위해 사용했지만,
compound component pattern을 사용한 컴포넌트가
오히려 각각 따로 컴포넌트를 정의한 것보다 길어질 수 있다.
이 꿀조합 컴포넌트만 하더라도
길이가 241줄에 도달한다.
(원래는 75줄이었다)
따라서, 이게 가장 좋은 방법인지
항상 충분히 고민하고 생각해 보자.
'펀잇' 카테고리의 다른 글
Meta OG image 교체가 안 된다면?! (1) | 2024.07.23 |
---|---|
[2탄] dialog 위에 토스트 뜨게 하기 (0) | 2024.05.07 |
펀잇 리뷰 작성 폼에서 웹 접근성 개선하기 (2) | 2023.11.12 |
최종 데모데이 후기 (2) | 2023.11.05 |
4, 5차 데모데이 피드백과 반영 (0) | 2023.11.01 |
댓글