Skip to content
5 changes: 2 additions & 3 deletions src/app/(crew)/my-crew/hosted/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Loader } from '@mantine/core';
import { useGetMyCrewHostedQuery } from '@/src/_queries/crew/my-crew-hosted-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import CrewSkeletonList from '@/src/components/common/skeleton/crew-skeleton-list';

export default function MyCrewHostedPage() {
const { data, isLoading, error, ref, isFetchingNextPage } = useInfiniteScroll(
Expand All @@ -15,9 +16,7 @@ export default function MyCrewHostedPage() {
<div>
<CrewCardList inWhere="my-crew" data={data ?? { pages: [], pageParams: [] }} />
{isLoading || isFetchingNextPage ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
<CrewSkeletonList num={6} column={1} />
) : (
<div ref={ref} className="h-[1px]" />
)}
Expand Down
5 changes: 2 additions & 3 deletions src/app/(crew)/my-crew/joined/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Loader } from '@mantine/core';
import { useGetMyCrewJoinedQuery } from '@/src/_queries/crew/my-crew-joined-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import CrewSkeletonList from '@/src/components/common/skeleton/crew-skeleton-list';

export default function MyCrewJoinedPage() {
const { data, isLoading, error, ref, isFetchingNextPage } = useInfiniteScroll(
Expand All @@ -15,9 +16,7 @@ export default function MyCrewJoinedPage() {
<div>
<CrewCardList inWhere="my-crew" data={data ?? { pages: [], pageParams: [] }} />
{isLoading || isFetchingNextPage ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
<CrewSkeletonList num={6} column={1} />
) : (
<div ref={ref} className="h-[1px]" />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@/src/_apis/auth/user-apis';
import { useUser } from '@/src/_queries/auth/user-queries';
import { useAuth } from '@/src/hooks/use-auth';
import ProfileSkeleton from '@/src/components/common/skeleton/profile-skeleton';
import ProfileCardPresenter from './presenter';

export default function ProfileCard() {
Expand Down Expand Up @@ -38,7 +39,7 @@ export default function ProfileCard() {
}
}, [user]);

if (userLoading || !isAuthChecked) return <div>로딩 중...</div>;
if (userLoading || !isAuthChecked) return <ProfileSkeleton />;
if (!user) return null;

const handleEdit = () => {
Expand Down
7 changes: 3 additions & 4 deletions src/app/(crew)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useRef, useState } from 'react';
import Image from 'next/image';
import { Divider, Loader, TextInput } from '@mantine/core';
import { Divider, Loader, Skeleton, TextInput } from '@mantine/core';
import { useGetCrewListQuery } from '@/src/_queries/crew/crew-list-queries';
import regionData from '@/src/data/region.json';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
Expand All @@ -11,6 +11,7 @@ import HeroCrew from '@/src/app/(crew)/_components/hero/hero-crew';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import Button from '@/src/components/common/input/button';
import DropDown from '@/src/components/common/input/drop-down';
import CrewSkeletonList from '@/src/components/common/skeleton/crew-skeleton-list';
import IcoSearch from '@/public/assets/icons/ic-search.svg';

export default function HomePage() {
Expand Down Expand Up @@ -133,9 +134,7 @@ export default function HomePage() {
<div className="mt-8 px-3 md:px-8 lg:px-11.5">
{data && <CrewCardList data={data} />}
{isLoading || isFetchingNextPage ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
<CrewSkeletonList num={6} column={2} />
) : (
<div ref={ref} className="h-[1px]" />
)}
Expand Down
18 changes: 18 additions & 0 deletions src/components/common/skeleton/crew-skeleton-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import CrewSkeleton from '../crew-skeleton';

interface CrewSkeletonListProps {
num: number;
column?: number;
}

export default function CrewSkeletonList({ num, column }: CrewSkeletonListProps) {
const columnStyle = column === 2 ? 'lg:grid-cols-2' : 'lg:grid-cols-1';
return (
<div className={`grid grid-cols-1 gap-2 ${columnStyle}`} aria-label="콘텐츠 로딩 중">
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<CrewSkeleton key={index} />
))}
</div>
);
}
15 changes: 15 additions & 0 deletions src/components/common/skeleton/crew-skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Skeleton } from '@mantine/core';

export default function CrewSkeleton() {
return (
<div className="flex overflow-hidden rounded-xl">
<Skeleton className="h-[203px] w-[230px]" />
<div className="relative flex flex-1 flex-col gap-2 p-6">
<Skeleton className="h-4 w-20" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-4 w-40" />
<Skeleton className="absolute bottom-6 left-6 right-6 h-2 w-auto" />
</div>
</div>
);
}
19 changes: 19 additions & 0 deletions src/components/common/skeleton/gathering-skeleton-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import GatheringSkeleton from '../gathering-skeleton';

interface GatheringSkeletonListProps {
num: number;
}

export default function GatheringSkeletonList({ num }: GatheringSkeletonListProps) {
return (
<div
className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3"
aria-label="콘텐츠 로딩 중"
>
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<GatheringSkeleton key={index} />
))}
Comment on lines +13 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

배열 인덱스를 key로 사용하는 것은 피해야 합니다.

현재 구현에서는 배열 인덱스를 key로 사용하고 있는데, 이는 React의 재조정(reconciliation) 과정에서 문제를 일으킬 수 있습니다. 스켈레톤 아이템의 경우 정적이므로 큰 문제가 되지 않을 수 있으나, 더 안전한 방법을 사용하는 것이 좋습니다.

- {[...Array(num)].map((_, index) => (
-   // eslint-disable-next-line react/no-array-index-key
-   <GatheringSkeleton key={index} />
- ))}
+ {Array.from({ length: num }, (_, index) => (
+   <GatheringSkeleton key={`skeleton-${index}`} />
+ ))}

또한, Array.from()을 사용하면 스프레드 연산자를 사용하는 것보다 더 명확하고 효율적입니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<GatheringSkeleton key={index} />
))}
{Array.from({ length: num }, (_, index) => (
<GatheringSkeleton key={`skeleton-${index}`} />
))}

</div>
);
}
16 changes: 16 additions & 0 deletions src/components/common/skeleton/gathering-skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Skeleton } from '@mantine/core';

export default function GatheringSkeleton() {
return (
<div className="flex flex-col overflow-hidden rounded-xl">
<Skeleton className="h-[160px] w-full" />
<div className="relative flex min-h-[184px] flex-col gap-2 p-4">
<Skeleton className="h-4 w-40" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-4 w-24" />
<Skeleton circle className="absolute right-4 top-4 h-8 w-8" />
<Skeleton className="absolute bottom-4 left-4 right-4 h-10 w-auto" />
</div>
</div>
);
}
17 changes: 17 additions & 0 deletions src/components/common/skeleton/my-gathering-skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Skeleton } from '@mantine/core';

export default function MyGatheringSkeleton() {
return (
<div className="flex gap-6 p-6">
<Skeleton className="h-28 w-28 rounded-xl md:h-32 md:w-32" />
<div className="relative flex flex-col gap-3">
<Skeleton className="h-4 w-40" />
<div className="flex gap-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-4 w-24" />
</div>
<Skeleton className="absolute bottom-0 h-4 w-24" />
</div>
</div>
);
}
Comment on lines +1 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

스켈레톤 컴포넌트가 현재 미사용 상태입니다

검증 결과, MyGatheringSkeleton 컴포넌트는 정의된 파일(src/components/common/skeleton/my-gathering-skeleton/index.tsx) 외에 다른 곳에서 사용되지 않고 있습니다. 이는 다음 두 가지 가능성을 시사합니다:

  • 새로 추가된 컴포넌트로 아직 사용되지 않은 상태
  • 더 이상 필요하지 않은 미사용 컴포넌트

개발자의 의도에 따라 다음 조치가 필요합니다:

  • 새로운 기능을 위한 컴포넌트라면 사용 계획 확인
  • 불필요한 컴포넌트라면 제거 고려
🔗 Analysis chain

컴포넌트 사용 패턴 확인 필요

이 스켈레톤 컴포넌트가 다른 페이지들과 일관되게 사용되고 있는지 확인이 필요합니다.


Let me try different commands to gather the necessary information.


Let me try one more search with different commands to find the component usage.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 스켈레톤 컴포넌트의 사용 패턴 확인

# MyGatheringSkeleton 컴포넌트의 사용처 확인
echo "MyGatheringSkeleton 사용 현황:"
rg "MyGatheringSkeleton" --type tsx

# 다른 스켈레톤 컴포넌트들과의 일관성 확인
echo "\n다른 스켈레톤 컴포넌트 현황:"
fd --type f ".*skeleton.*\.tsx$" src/components

Length of output: 223


Script:

#!/bin/bash
# MyGatheringSkeleton 컴포넌트 사용처 확인
echo "MyGatheringSkeleton 사용 현황:"
rg "MyGatheringSkeleton" -t ts -t tsx

# 다른 스켈레톤 컴포넌트 검색
echo -e "\n스켈레톤 컴포넌트 파일 목록:"
find src/components -type f -name "*skeleton*.tsx"

# 스켈레톤 컴포넌트 임포트 패턴 확인
echo -e "\n스켈레톤 컴포넌트 임포트 패턴:"
rg "import.*Skeleton" -t ts -t tsx

# MyGatheringSkeleton 구현 확인
echo -e "\nMyGatheringSkeleton 구현 확인:"
ast-grep --pattern 'export default function MyGatheringSkeleton() { $$$ }'

Length of output: 1965


Script:

#!/bin/bash
# 전체 코드베이스에서 MyGatheringSkeleton 문자열 검색
echo "MyGatheringSkeleton 사용 현황:"
find . -type f -exec grep -l "MyGatheringSkeleton" {} \;

# 스켈레톤 관련 파일 검색 (대소문자 구분 없이)
echo -e "\n스켈레톤 관련 파일:"
find . -type f -iname "*skeleton*.tsx" -o -iname "*skeleton*.ts"

# Mantine Skeleton 임포트 검색
echo -e "\nMantine Skeleton 임포트:"
find . -type f -exec grep -l "@mantine/core.*Skeleton" {} \;

Length of output: 187

16 changes: 16 additions & 0 deletions src/components/common/skeleton/my-review-skeleton-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import MyReviewSkeleton from '../my-review-skeleton';

interface MyReviewSkeletonListProps {
num: number;
}

export default function MyReviewSkeletonList({ num }: MyReviewSkeletonListProps) {
return (
<div className="grid grid-cols-1 gap-6" aria-label="콘텐츠 로딩 중">
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<MyReviewSkeleton key={index} />
))}
</div>
);
}
Comment on lines +7 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

컴포넌트 구현에 대한 개선 제안

현재 구현에서 몇 가지 개선할 점이 있습니다:

  1. 배열 인덱스를 key로 사용하는 것은 React의 성능 최적화에 좋지 않을 수 있습니다.
  2. num prop에 대한 유효성 검사가 필요합니다.
  3. 배열 생성 로직을 더 명확하게 표현할 수 있습니다.

다음과 같이 개선해보세요:

 interface MyReviewSkeletonListProps {
   num: number;
 }

 export default function MyReviewSkeletonList({ num }: MyReviewSkeletonListProps) {
+  const skeletonCount = Math.max(0, Math.floor(num));
   return (
     <div className="grid grid-cols-1 gap-6" aria-label="콘텐츠 로딩 중">
-      {[...Array(num)].map((_, index) => (
-        // eslint-disable-next-line react/no-array-index-key
-        <MyReviewSkeleton key={index} />
+      {Array.from({ length: skeletonCount }, (_, index) => (
+        <MyReviewSkeleton key={`skeleton-${index}`} />
       ))}
     </div>
   );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function MyReviewSkeletonList({ num }: MyReviewSkeletonListProps) {
return (
<div className="grid grid-cols-1 gap-6" aria-label="콘텐츠 로딩 중">
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<MyReviewSkeleton key={index} />
))}
</div>
);
}
interface MyReviewSkeletonListProps {
num: number;
}
export default function MyReviewSkeletonList({ num }: MyReviewSkeletonListProps) {
const skeletonCount = Math.max(0, Math.floor(num));
return (
<div className="grid grid-cols-1 gap-6" aria-label="콘텐츠 로딩 중">
{Array.from({ length: skeletonCount }, (_, index) => (
<MyReviewSkeleton key={`skeleton-${index}`} />
))}
</div>
);
}

16 changes: 16 additions & 0 deletions src/components/common/skeleton/my-review-skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Skeleton } from '@mantine/core';

export default function MyReviewSkeleton() {
return (
<div className="flex flex-col">
<Skeleton className="h-6 w-32" />
<div className="relative flex flex-col gap-2 p-6">
<Skeleton className="mb-4 h-4 w-40" />
<Skeleton className="h-6 w-32" />
<Skeleton className="h-4 w-60" />
<Skeleton className="absolute bottom-6 h-4 w-20" />
<Skeleton className="absolute bottom-6 right-6 h-9 w-30" />
</div>
</div>
);
}
13 changes: 13 additions & 0 deletions src/components/common/skeleton/profile-skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Skeleton } from '@mantine/core';

export default function ProfileSkeleton() {
return (
<div className="flex items-center gap-6.5" aria-label="콘텐츠 로딩 중">
<Skeleton circle className="h-28 w-28" />
<div className="flex flex-col gap-3">
<Skeleton className="h-6 w-40" />
<Skeleton className="h-4 w-36" />
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ReviewableReviewSkeleton from '../reviewable-review-skeleton';

interface ReviewableReviewSkeletonListProps {
num: number;
}

export default function ReviewableReviewSkeletonList({ num }: ReviewableReviewSkeletonListProps) {
return (
<div className="grid grid-cols-1 gap-12" aria-label="콘텐츠 로딩 중">
{[...Array(num)].map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<ReviewableReviewSkeleton key={index} />
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Skeleton } from '@mantine/core';

export default function ReviewableReviewSkeleton() {
return (
<div className="flex gap-5">
<Skeleton className="h-[166px] w-[230px] rounded-xl" />
<div className="relative flex flex-1 flex-col gap-4">
<Skeleton className="h-4 w-40" />
<Skeleton className="h-4 w-20" />
<Skeleton className="absolute bottom-0 h-4 w-28" />
<Skeleton className="absolute bottom-0 right-0 h-10 w-28 rounded-xl" />
</div>
</div>
);
}
8 changes: 7 additions & 1 deletion src/components/gathering-list/liked-list-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { toast } from 'react-toastify';
import { addLike, removeLike } from '@/src/_apis/liked/liked-apis';
import { useGetLikedListQuery } from '@/src/_queries/liked/liked-queries';
import { ApiError } from '@/src/utils/api';
import GatheringSkeletonList from '../common/skeleton/gathering-skeleton-list';
import LikedListPresenter from './liked-list-presenter';

export default function LikedList() {
Expand Down Expand Up @@ -37,7 +38,12 @@ export default function LikedList() {
setPage(newPage);
};

if (isLoading) return <div>로딩중...</div>;
if (isLoading)
return (
<div className="mx-auto max-w-[1200px] px-4">
<GatheringSkeletonList num={6} />
</div>
);

// 에러 처리: error 또는 gatheringData가 undefined일 경우
if (error || gatheringData === undefined) {
Expand Down
Loading