반응형
멋사사이트를 만드는 중 , 다음과 같은 3가지 아카이빙 페이지(프로젝트 아카이빙, 추억 아카이빙, 세션 아카이빙)을 제작해야 했다.
https://github.com/cau-likelion-org/cau-likelion-next/pull/26
해당 페이지들은 모두 동일하게 아래와 같은 Card형식을 사용하고 있다.
다만, 사진 아래의 내용이 세션카드냐, 프로젝트 카드냐, 추억 카드냐에 따라 1차세션, 아이디어톤, 날짜로 각 내용이 달라야 한다.
그래서 처음에는 이렇게 타입을 만들어주었다. category에 따라 그 내용이 달라지게 만든 것이다.
export interface IArchivingData {
id: number;
title: string;
category: string;
thumbnail: string;
dev_stack?: number[];
description?: string;
}
그리고 Archiving이라는 카드를 찍어주는 컴포넌트를 만들기 위해 api를 통해 받아온 데이터 타입을 이렇게 설계했다.
export type ArchivingArrayType = Record<string, IArchivingData[]>;
{
9:[
{
id:1,
title:"프로젝트이름",
dev_stack:[1,2,3,9,4],
description:"설명",
category:"해커톤"
thumbnail:"https://어쩌구~"
},
{
},
...
],
10:[{}],
11:[{},{}],
}
이런식의 데이터를
이렇게 찍어주는 것이다.
그런데 아래의 타입에 따르면 category라는 프로퍼티 키에 세션카드인 경우 몇차세션인지가, 추억카드인 경우는 날짜가 들어가게된다.
export interface IArchivingData {
id: number;
title: string;
category: string;
thumbnail: string;
dev_stack?: number[];
description?: string;
}
계속해서 떠오르는 ISP때문에 이걸 개선하기로 했다.
공통 부분을 IArchivingData로 냅두고, extends를 통해 바뀌는 부분을 해결한다.
export interface IArchivingData {
id: number;
title: string;
thumbnail: string;
description?: string;
}
export interface IProjectData extends IArchivingData {
category: string;
dev_stack: number[];
}
export interface ISessionData extends IArchivingData {
degree: number;
}
export interface IGalleryData extends IArchivingData {
date: string;
}
여기까진 순조롭다.
문제는 아래의 녀석과 실제 데이터를 찍어주는 컴포넌트들이다.
export type ArchivingArrayType = Record<string, IArchivingData[]>;
이녀석을 제네릭을 써서 고쳐줬다.
export type ArchivingArrayType<T> = Record<string, T[]>;
컴포넌트 역시 제네릭을 써서, 각 타입에 맞는 타입을 자동적으로 수용할 수 있게 만들었다.
const Archiving = <Type extends ISessionData | IProjectData | IGalleryData>({
archivingType,archivingIndex,archivingData,
}: {
archivingType: ArchivingType;
archivingIndex: string;
archivingData: Type[];
}){
...
}
세부 객체 데이터들은 다음과 같이 분류해서 화면에 렌더링 해주었다.
const getIndexMessageAndURL = (archivingType: ArchivingType, archivingIndex: number) => {
if (archivingType == 'session') {
return ['/session', TRACK[archivingIndex]];
}
if (archivingType == 'gallery') {
return ['/gallery', `${archivingIndex}년`];
}
return ['/project', `${archivingIndex}기`];
};
const getType = <Type extends ISessionData | IProjectData | IGalleryData>(data: Type) => {
if ('category' in data) return data.category;
if ('degree' in data) return data.degree;
if ('date' in data) return data.date;
};
랜더링 컴포넌트
...
<CardWrapper>
{archivingData.map((data, index) => (
<Card
key={index}
id={data.id}
link={link}
thumbnail={data.thumbnail}
title={data.title}
description={data.description}
dev_stack={'dev_stack' in data ? data.dev_stack : undefined}
category={getType(data)}
/>
))}
</CardWrapper>
...
반응형