🤷🏻♀️ 제목이 필터링 기능 잔혹사인 이유는?
그냥 내가 혼자 삽질을 하다가 두 번 일하는 잔혹한 일이 벌어졌기때문
홈페이지 카테고리 필터링 기능구현을 맡은 나
이미 필터링 기능을 구현해 본 나는 자신만만하게 이전에 했던 코드를 참고해서 필터링 기능을 구현하기 시작했다.
그런데? 문제가 생겨버렸다.
아직 백엔드의 데이터를 사용하기 전 간단하게 목데이터를 만들어 사용하고 있었는데 내가 만든 필터링 기능이 전체 데이터를 필터링 하는게 아니라 이미 받아온 데이터에 한해서 필터링을 하고 있던 것이다.
그니까 무한스크롤을 구현하기로 한 우리 프로젝트에서 1페이지에서만 받아오는 데이터만 필터링 할 수 있게 만들었다는것..!! ㅠ
자신만만해 했지만 꽤나 걸린 코드를 다 고칠 수 밖에 없었다는 슬픈이야기.. 다음에는..... 깊게 생각하자...! ㅠ
일단 레이아웃으로 구현해 놓은 카테고리!
카테고리 이동은 Swiper 라이브러리를 사용해서 양쪽 화살표를 클릭하면 이동할 수 있게 했다.
const filters = [
"전체",
"관광호텔",
"콘도미니엄",
"유스호스텔",
"펜션",
"모텔",
"민박",
"게스트하우스",
"홈스테이",
"서비스드레지던스",
"한옥",
];
const categoryMap: { [key: string]: string } = {
관광호텔: "B02010100",
콘도미니엄: "B02010500",
유스호스텔: "B02010600",
펜션: "B02010700",
모텔: "B02010900",
민박: "B02011000",
게스트하우스: "B02011100",
홈스테이: "B02011200",
서비스드레지던스: "B02011300",
한옥: "B02011600",
};
일단 카테고리는 배열로 만들어놨다. 백엔드에서 사용하는 공공 API는 위에 있는 문자로 되어있어서 사용하기위해 따로 객체로 만들어 줬다.
...
export default function HomePage() {
const [filter, setFilter] = useState(filters[0]);
const {
data: accommodation,
...
} = useInfiniteQuery({
queryKey: ["accommodation"],
queryFn: getAccommodations,
...
});
...
const handleFilterChange = (selectedFilter: string) => {
setFilter(selectedFilter);
};
return (
<div className="p-4">
<FilterCategory filters={filters} />
{accommodation.pages && (
<FilterCategory filters={filters} onFilterChange={handleFilterChange} />
{accommodation.pages && (
<ul className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-5 gap-y-4">
{accommodation?.pages.map(page =>
{accommodation.map(page =>
page.map((item: AccommodationInfo, index: number) => {
if (item.length == index + 1) {
return <AccommodationCard innerRef={ref} key={index} accommodation={item} />;
}
return <AccommodationCard key={index} accommodation={item} />;
}),
)}
</ul>
)}
...
</div>
);
}
필터 카테고리는 따로 컴포넌트로 만들어서 사용했고 filter 상태를 이용해서 해당 카테고리를 클릭하면 해당 상태값이 업데이트 될 수 있게 했다.
...
const filteredAccommodations = getFilteredItems(accommodation.pages, filter);
...
function getFilteredItems(accommodation: AccommodationInfo[][], filter: string) {
if (filter === "전체") {
return accommodation;
} else {
const categoryCode = categoryMap[filter];
return accommodation.map(item => item.filter(it => it.category === categoryCode));
}
}
그 후에 필터링을 위해 필터 함수를 만들어 사용했다.
완성된 코드!
import { useInfiniteQuery } from "@tanstack/react-query";
import { getAccommodations } from "../util/http";
import AccommodationCard from "../components/homepage/AccommodationCard";
import FilterCategory from "../components/homepage/FilterCategory";
import { useEffect, useState } from "react";
import { AccommodationInfo } from "../types/AccommodationInfo";
const filters = [
"전체",
"관광호텔",
"콘도미니엄",
"유스호스텔",
"펜션",
"모텔",
"민박",
"게스트하우스",
"홈스테이",
"서비스드레지던스",
"한옥",
];
const categoryMap: { [key: string]: string } = {
관광호텔: "B02010100",
콘도미니엄: "B02010500",
유스호스텔: "B02010600",
펜션: "B02010700",
모텔: "B02010900",
민박: "B02011000",
게스트하우스: "B02011100",
홈스테이: "B02011200",
서비스드레지던스: "B02011300",
한옥: "B02011600",
};
export default function HomePage() {
const [filter, setFilter] = useState(filters[0]);
const {
data: accommodation,
...
} = useInfiniteQuery({
queryKey: ["accommodation"],
queryFn: getAccommodations,
...
});
...
const handleFilterChange = (selectedFilter: string) => {
setFilter(selectedFilter);
};
const filteredAccommodations = getFilteredItems(accommodation.pages, filter);
return (
<div className="p-4">
<FilterCategory filters={filters} />
{accommodation.pages && (
<FilterCategory filters={filters} onFilterChange={handleFilterChange} />
{filteredAccommodations && (
<ul className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-5 gap-y-4">
{accommodation?.pages.map(page =>
{filteredAccommodations.map(page =>
page.map((item: AccommodationInfo, index: number) => {
if (item.length == index + 1) {
return <AccommodationCard innerRef={ref} key={index} accommodation={item} />;
}
return <AccommodationCard key={index} accommodation={item} />;
}),
)}
</ul>
)}
...
</div>
);
}
function getFilteredItems(accommodation: AccommodationInfo[][], filter: string) {
if (filter === "전체") {
return accommodation;
} else {
const categoryCode = categoryMap[filter];
return accommodation.map(item => item.filter(it => it.category === categoryCode));
}
}
뿌듯해 하며 커밋했던 과거의 나.
지워.
필터링 기능을 수행하기 위해 만들어 줬던 filteredAccommodations, getFilteredItems 함수들을 다 지워줬다.
대신 필터링을 하는 부분을 네트워크 통신하는 부분에 가져와서 해당 필터에 따라서 데이터를 불러올 수 있게 만들었다.
export async function getAccommodations(pageParam: number, category: string | null) {
let url;
if (!category) {
url = "/api/accommodations";
} else {
const categoryCode = categoryMap[category];
url = `/api/accommodations/category/${categoryCode}`;
}
try {
const res = await fetch(url + `?page=${pageParam}`);
const data = await res.json();
return data;
} catch (err) {
console.error("Error:", err);
}
}
그렇게 완성된 필터링 기능!
이제 교훈을 얻었으니 다음부터는 꼭 내가 구현하는 기능에 대해 충분히 생각하고 계획도 짜면서 시작해야겠다.
~ the end ~
'Front-end > etc' 카테고리의 다른 글
Error [ERR_REQUIRE_ESM]: require() of ES Module... 해결하기 (0) | 2024.05.09 |
---|---|
카테고리 상태값이 초기값으로 돌아가는 이유? (0) | 2024.04.15 |
Mock Service Worker(MSW)로 API 목킹하기(feat.React) (0) | 2024.03.22 |
Firebase로 회원가입 & 로그인 기능 구현하기 - Authentication (0) | 2024.03.19 |
Firebase 시작하기 - 프로젝트 생성, Realtime Database (0) | 2024.03.18 |