반응형
리팩토링 전 📖
리팩토링 전 코드는 컴포넌트 내부에 복잡한 로직들이 섞여있어 가독성과 유지보수성이 떨어졌습니다.
특히 폴리곤을 그리는 `좌표 데이터 처리`와 `mouseover``mouseout` 이벤트 처리 로직이 분리되어 있지 않고 중복되어 있어서 재사용성이 부족했습니다.
✨그래서 리팩토링 하기로 결정을 했습니다! ✨
리팩토링 후 📖
"use client";
const KakaoMapLoader = () => {
useKakaoLoader();
const [location, setLocation] = useState({
center: { lat: 35.90701, lng: 127.570667 },
isPanto: true,
});
const [selectedPath, setSelectedPath] = useState([]);
const { geoList, setGeoList } = useGeoData(); // 커스텀 훅 사용
// hover 상태 변경 함수 통합
const handleHoverState = (key: number, isHover: boolean) => {
setGeoList((prevGeoList) =>
prevGeoList.map((area) =>
area.key === key ? { ...area, isHover } : area
)
);
};
return (
<Map
id="map"
center={location.center}
isPanto={location.isPanto}
className="w-[100vw] h-[100vh] relative"
level={12}
>
{geoList.map((item, index) => {
const { key, path, isHover } = item;
const color = MAP_COLOR[index];
return (
<Polygon
key={key}
path={path}
strokeWeight={2}
strokeColor={color}
strokeOpacity={0.8}
fillColor={isHover ? color : "#ffffff"}
fillOpacity={0.8}
onMouseover={() => handleHoverState(key, true)}
onMouseout={() => handleHoverState(key, false)}
/>
);
})}
</Map>
);
};
export default KakaoMapLoader;
먼저 `mouseover`와 `moseout`로직을 하나의 함수로 통합해 중복되는 로직을 제거했습니다.
// hover 상태 변경 함수 통합
const handleHoverState = (key: number, isHover: boolean) => {
setGeoList((prevGeoList) =>
prevGeoList.map((area) =>
area.key === key ? { ...area, isHover } : area
)
);
};
return (
<Polygon
onMouseover={() => handleHoverState(key, true)}
onMouseout={() => handleHoverState(key, false)}
/>
)
그리고 비즈니스 로직을 컴포넌트에서 분리해 `useGeoData` 커스텀 훅을 만들어서 데이터를 가져오는 로직을 분리했습니다.
const { geoList, setGeoList } = useGeoData(); // 커스텀 훅 사용
const useGeoData = () => {
const [geoList, setGeoList] = useState<GeoData[]>([]);
useEffect(() => {
const data = pathListFormatter();
setGeoList(data);
}, []);
return { geoList, setGeoList };
};
export default useGeoData;
기존에 사용하던 폴리곤 좌표 데이터 처리하던 로직을 `pathListFormatter` 유틸 함수로 분리했습니다. 그리고 `getPolygonPathList`와 `getMultiPolygonPathList`로 좌표 형식을 처리했습니다.
// 행정구역 PathList 가져오기
export const pathListFormatter = () => {
const { features } = coordRegionCode;
const data = features.map((item) => {
const { geometry, properties } = item;
const { CTP_KOR_NM } = properties;
const { coordinates, type } = geometry;
const pathList =
type === "Polygon"
? getPolygonPathList(coordinates)
: type === "MultiPolygon"
? getMultiPolygonPathList(coordinates)
: [];
return {
name: CTP_KOR_NM,
path: pathList,
isHover: false,
key: Math.random(),
};
});
return data;
};
// Polygon pathList 포멧 (3차원 배열)
const getPolygonPathList = (coordinates: CoordinatesType) => {
return coordinates.map((areaList) =>
areaList.map(([lng, lat]) => ({ lng: Number(lng), lat: Number(lat) }))
);
};
// MultiPolygon pathList 포멧 (4차원 배열)
const getMultiPolygonPathList = (coordinates: CoordinatesType) => {
return coordinates.flatMap((polygon) =>
polygon.map(
(areaList) =>
areaList
.map((area) => {
if (Array.isArray(area)) {
const [lng, lat] = area;
return { lng: Number(lng), lat: Number(lat) };
}
return null; // null을 반환하는 대신 에러를 방지
})
.filter((item): item is { lng: number; lat: number } => item !== null) // null 제거
)
);
};
이를 통해 컴포넌트에는 렌더링에만 집중하고 비지니스 로직은 별도 파일로 분리해 가독성과 재사용성을 높였습니다.
회고 🧐
이번 리팩토링을 통해 컴포넌트가 복잡한 로직을 처리하기보다는 데이터와 UI의 분리를 극대화할 수 있었습니다. 특히, 이벤트 로직을 통합하면서 코드 중복을 줄이고 간결하게 표현한 것이 큰 성과라고 생각합니다. 앞으로도 지속적으로 코드 구조 개선을 통해 유지보수성과 가독성을 높여나가야겠습니다.
아직 많이 부족하기 때문에 조언은 언제나 환영입니다~!!
반응형
'공부 > Next' 카테고리의 다른 글
[리팩토링] Icon 컴포넌트 리팩토링 (0) | 2024.11.02 |
---|---|
Next 커스텀 훅을 사용한 모달창 기능 구현 (1) | 2024.11.01 |
[리팩토링] 데이터 로직 분리 및 서버 상태 관리 최적화 (0) | 2024.10.28 |
Next 카카오맵을 활용한 시도별 가로 스크롤 버튼 이동 구현 (0) | 2024.10.28 |
Next 카카오 맵 행정구역 나누기 (1) | 2024.10.23 |
Next 카카오 맵 구현 (0) | 2024.10.23 |
[Next, Supabase Auth] 이메일, 소셜 로그인 기능 구현 및 트리거 설정 (2) | 2024.10.14 |
Next.js 알아보기 8 (Caching - 어려움 주의) (0) | 2024.09.27 |