diff --git a/src/components/Tours/ToursCategory.tsx b/src/components/Tours/ToursCategory.tsx
index 6a7d74d6..c3507ad5 100644
--- a/src/components/Tours/ToursCategory.tsx
+++ b/src/components/Tours/ToursCategory.tsx
@@ -1,20 +1,34 @@
import { RegionTypes, ToursCategoryProps } from '@/@types/tours.types';
import ToursCategoryItem from './ToursCategoryItem';
import { getPopularRegion } from '@api/region';
-import { useQuery } from '@tanstack/react-query';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
+import ToursCategoryItemSkeleton from './ToursCategoryItemSkeleton';
+import { v4 as uuidv4 } from 'uuid';
+import { useQuery } from '@tanstack/react-query';
+import { useEffect, useState } from 'react';
const ToursCategory = ({
selectedRegion,
setSelectedRegion,
}: ToursCategoryProps) => {
- const regionsQuery = useQuery({
+ const { data, isLoading, error } = useQuery({
queryKey: ['regions'],
queryFn: () => getPopularRegion(),
});
- if (regionsQuery.error) {
+ const [showSkeleton, setShowSkeleton] = useState(isLoading);
+
+ useEffect(() => {
+ if (isLoading) {
+ setShowSkeleton(true);
+ } else {
+ const timer = setTimeout(() => setShowSkeleton(false), 200);
+ return () => clearTimeout(timer);
+ }
+ }, [isLoading]);
+
+ if (error) {
console.log('error - 예외 처리');
}
@@ -28,18 +42,32 @@ const ToursCategory = ({
};
// '전체' 항목 추가
- const regionsData = regionsQuery.data?.data.data.regions ?? [];
+ const regionsData = data?.data.data.regions ?? [];
const regions = [
- { name: '전체', areaCode: 0, subAreaCode: 0 },
+ { name: '전체', areaCode: uuidv4(), subAreaCode: 0 },
...regionsData,
];
+ if (showSkeleton) {
+ return (
+
+
+ {Array.from({ length: 10 }, (_, index) => (
+
+
+
+ ))}
+
+
+ );
+ }
+
return (
- {regions.map((region: RegionTypes, index: number) => {
+ {regions.map((region: RegionTypes) => {
return (
-
+
{
+ return (
+
+ );
+};
+
+export default ToursCategoryItemSkeleton;
diff --git a/src/components/Tours/ToursItemSkeleton.tsx b/src/components/Tours/ToursItemSkeleton.tsx
new file mode 100644
index 00000000..ca91d5d4
--- /dev/null
+++ b/src/components/Tours/ToursItemSkeleton.tsx
@@ -0,0 +1,16 @@
+const ToursItemSkeleton = () => {
+ return (
+
+ );
+};
+
+export default ToursItemSkeleton;
diff --git a/src/components/Tours/ToursList.tsx b/src/components/Tours/ToursList.tsx
index 10a2f6cc..700c343f 100644
--- a/src/components/Tours/ToursList.tsx
+++ b/src/components/Tours/ToursList.tsx
@@ -1,26 +1,40 @@
import { TourType, ToursListProps } from '@/@types/tours.types';
-import ToursItem from './ToursItem';
import { getTours } from '@api/tours';
import { useInfiniteQuery } from '@tanstack/react-query';
+import React, { useEffect, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroller';
-import React from 'react';
+import { v4 as uuidv4 } from 'uuid';
+import ToursItem from './ToursItem';
+import ToursItemSkeleton from './ToursItemSkeleton';
const ToursList = ({ selectedRegion }: ToursListProps) => {
- const { fetchNextPage, hasNextPage, data, error } = useInfiniteQuery({
- queryKey: ['tours', selectedRegion],
- queryFn: ({ pageParam = 0 }) => getTours(selectedRegion, pageParam, 10),
- initialPageParam: 0,
- getNextPageParam: (lastPage) => {
- const currentPage = lastPage?.data.data.pageable.pageNumber;
- const totalPages = lastPage?.data.data.totalPages;
-
- if (currentPage < totalPages - 1) {
- return currentPage + 1;
- }
-
- return undefined;
- },
- });
+ const { fetchNextPage, hasNextPage, data, isLoading, error } =
+ useInfiniteQuery({
+ queryKey: ['tours', selectedRegion],
+ queryFn: ({ pageParam = 0 }) => getTours(selectedRegion, pageParam, 10),
+ initialPageParam: 0,
+ getNextPageParam: (lastPage) => {
+ const currentPage = lastPage?.data.data.pageable.pageNumber;
+ const totalPages = lastPage?.data.data.totalPages;
+
+ if (currentPage < totalPages - 1) {
+ return currentPage + 1;
+ }
+
+ return undefined;
+ },
+ });
+
+ const [showSkeleton, setShowSkeleton] = useState(isLoading);
+
+ useEffect(() => {
+ if (isLoading) {
+ setShowSkeleton(true);
+ } else {
+ const timer = setTimeout(() => setShowSkeleton(false), 200);
+ return () => clearTimeout(timer);
+ }
+ }, [isLoading]);
if (error) {
return 데이터를 불러오는 중 오류가 발생했습니다.
;
@@ -32,18 +46,27 @@ const ToursList = ({ selectedRegion }: ToursListProps) => {
loadMore={() => fetchNextPage()}
hasMore={hasNextPage}
loader={
-
- Loading ...
+
}>
-
- {data?.pages.map((group, index) => (
-
- {group?.data.data.content.map((tour: TourType) => (
-
+
+ {showSkeleton
+ ? Array.from({ length: 10 }, (_, index) => (
+
+ ))
+ : data?.pages.map((group) => (
+
+ {group?.data.data.content.map((tour: TourType) => (
+
+ ))}
+
))}
-
- ))}
);
diff --git a/src/components/common/nav/Nav.tsx b/src/components/common/nav/Nav.tsx
index cf531adb..96a76421 100644
--- a/src/components/common/nav/Nav.tsx
+++ b/src/components/common/nav/Nav.tsx
@@ -16,13 +16,13 @@ const Nav = () => {
- 홈
+ 홈
navigate('/')}
className="cursor-pointer flex-col items-center justify-center px-2">
-
일정
+
일정
navigate('/')}
@@ -30,7 +30,7 @@ const Nav = () => {
-
찜
+
찜
navigate('/signin')}
@@ -38,7 +38,7 @@ const Nav = () => {
-
내정보
+
내정보