diff --git a/src/app/(after-login)/dashboard/[dashboardid]/_components/Column.tsx b/src/app/(after-login)/dashboard/[dashboardid]/_components/Column.tsx
index 2311a51..8d63a45 100644
--- a/src/app/(after-login)/dashboard/[dashboardid]/_components/Column.tsx
+++ b/src/app/(after-login)/dashboard/[dashboardid]/_components/Column.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState, useRef } from "react";
+import { useIntersection } from "@/lib/hooks/useIntersection";
import { DashboardColumn, TaskCardList } from "@/lib/types";
import { fetchTaskCardList } from "@/lib/apis/cardsApi";
import { TOKEN_1 } from "@/lib/constants/tokens";
@@ -50,26 +51,11 @@ export default function Column({ id, title }: DashboardColumn) {
handleLoad();
}, []);
- useEffect(() => {
- if (isLast) return;
-
- const observer = new IntersectionObserver(
- (entries) => {
- if (entries[0].isIntersecting) {
- handleLoad();
- }
- },
- { threshold: 0.5 }
- );
-
- const current = observerRef.current;
- if (current) observer.observe(current);
-
- return () => {
- if (current) observer.unobserve(current);
- observer.disconnect();
- };
- }, [cursorId, isLoading, isLast]);
+ useIntersection({
+ target: observerRef,
+ onIntersect: handleLoad,
+ disabled: isLast,
+ });
return (
diff --git a/src/app/(after-login)/mydashboard/layout.tsx b/src/app/(after-login)/mydashboard/layout.tsx
index 1235300..4f4437f 100644
--- a/src/app/(after-login)/mydashboard/layout.tsx
+++ b/src/app/(after-login)/mydashboard/layout.tsx
@@ -4,13 +4,18 @@ import { TOKEN_1 } from "@/lib/constants/tokens";
import DashboardMenu from "@/components/layout/navbar/DashboardMenu";
import UserMenu from "@/components/layout/navbar/UserMenu";
+const PAGE_SIZE = 15;
+
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
- // 가장 첫 번째 페이지 리스트 불러오도록 나중에 수정
- const { dashboards } = await fetchDashboardList(TOKEN_1);
+ const { dashboards } = await fetchDashboardList({
+ token: TOKEN_1,
+ page: 1,
+ size: PAGE_SIZE,
+ });
const firstDashboardId = dashboards[0]?.id;
diff --git a/src/app/(after-login)/mypage/layout.tsx b/src/app/(after-login)/mypage/layout.tsx
index d990c3b..b8e4b91 100644
--- a/src/app/(after-login)/mypage/layout.tsx
+++ b/src/app/(after-login)/mypage/layout.tsx
@@ -4,13 +4,18 @@ import { TOKEN_1 } from "@/lib/constants/tokens";
import DashboardMenu from "@/components/layout/navbar/DashboardMenu";
import UserMenu from "@/components/layout/navbar/UserMenu";
+const PAGE_SIZE = 15;
+
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
- // 가장 첫 번째 페이지 리스트 불러오도록 나중에 수정
- const { dashboards } = await fetchDashboardList(TOKEN_1);
+ const { dashboards } = await fetchDashboardList({
+ token: TOKEN_1,
+ page: 1,
+ size: PAGE_SIZE,
+ });
const firstDashboardId = dashboards[0]?.id;
diff --git a/src/components/layout/sidebar/SideMenuItem.tsx b/src/components/layout/sidebar/SideMenuItem.tsx
index dfed3c5..f1580fe 100644
--- a/src/components/layout/sidebar/SideMenuItem.tsx
+++ b/src/components/layout/sidebar/SideMenuItem.tsx
@@ -1,5 +1,3 @@
-"use client";
-
import { useIsMobile } from "@/lib/hooks/useCheckViewport";
import { useDashboardStore } from "@/lib/store/useDashboardStore";
import { useRouter } from "next/navigation";
@@ -26,7 +24,7 @@ export default function SideMenuItem({
onClick={() => {
router.push(`/dashboard/${id}`);
}}
- className="flex items-center p-4 rounded hover:bg-violet-8 tablet:px-[10px] tablet:py-2 pc:p-3"
+ className="flex items-center w-full p-4 rounded hover:bg-violet-8 tablet:px-[10px] tablet:py-2 pc:p-3"
style={isCurrent ? { background: "#f1effd" } : {}}
disabled={isCurrent}
>
diff --git a/src/components/layout/sidebar/SideMenuList.tsx b/src/components/layout/sidebar/SideMenuList.tsx
index 4105824..3ed3f90 100644
--- a/src/components/layout/sidebar/SideMenuList.tsx
+++ b/src/components/layout/sidebar/SideMenuList.tsx
@@ -1,21 +1,62 @@
+"use client";
+
+import { useEffect, useState, useRef } from "react";
+import { useIntersection } from "@/lib/hooks/useIntersection";
import { DashboardList } from "@/lib/types";
import { fetchDashboardList } from "@/lib/apis/dashboardsApi";
import { TOKEN_1 } from "@/lib/constants/tokens";
import SideMenuItem from "./SideMenuItem";
-export default async function SideMenuList() {
- const { dashboards, totalCount, cursorId } =
- await fetchDashboardList(TOKEN_1);
- const items: DashboardList[] = dashboards;
+const PAGE_SIZE = 15;
+
+export default function SideMenuList() {
+ const [items, setItems] = useState
([]);
+ const [page, setPage] = useState(1);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isLast, setIsLast] = useState(false);
+ const observerRef = useRef(null);
+
+ const handleLoad = async () => {
+ if (isLoading || isLast) return;
+ setIsLoading(true);
+
+ try {
+ const { dashboards: newDashboards } = await fetchDashboardList({
+ token: TOKEN_1,
+ size: PAGE_SIZE,
+ page,
+ });
+
+ if (newDashboards.length === 0) {
+ setIsLast(true);
+ } else {
+ setItems((prev) => [...prev, ...newDashboards]);
+ setPage((prev) => prev + 1);
+ }
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ handleLoad();
+ }, []);
- // 해당 값들 사용하게 되면 지울 테스트 코드들
- console.log(totalCount);
- console.log(cursorId);
+ useIntersection({
+ target: observerRef,
+ onIntersect: handleLoad,
+ disabled: isLast,
+ });
return (
-
- {items.map((item) => (
-
+
+ {items.map((item, index) => (
+
+
+
))}
);
diff --git a/src/components/layout/sidebar/index.tsx b/src/components/layout/sidebar/index.tsx
index 22dd3cc..6666d95 100644
--- a/src/components/layout/sidebar/index.tsx
+++ b/src/components/layout/sidebar/index.tsx
@@ -5,11 +5,11 @@ import SideMenuList from "./SideMenuList";
export default function Sidebar() {
return (
-
+
-
+
diff --git a/src/lib/apis/dashboardsApi.ts b/src/lib/apis/dashboardsApi.ts
index d32aa35..df6c3f1 100644
--- a/src/lib/apis/dashboardsApi.ts
+++ b/src/lib/apis/dashboardsApi.ts
@@ -1,8 +1,16 @@
import { BASE_URL } from "@/lib/constants/urls";
-export async function fetchDashboardList(token: string) {
+export async function fetchDashboardList({
+ token,
+ page,
+ size,
+}: {
+ token: string;
+ page: number;
+ size: number;
+}) {
const res = await fetch(
- `${BASE_URL}/dashboards?navigationMethod=pagination&page=1&size=10`,
+ `${BASE_URL}/dashboards?navigationMethod=pagination&page=${page}&size=${size}`,
{
headers: {
Accept: "application/json",
diff --git a/src/lib/hooks/useIntersection.ts b/src/lib/hooks/useIntersection.ts
new file mode 100644
index 0000000..467d3b8
--- /dev/null
+++ b/src/lib/hooks/useIntersection.ts
@@ -0,0 +1,38 @@
+"use client";
+
+import { useEffect } from "react";
+
+interface UseIntersectionProps {
+ target: React.RefObject
;
+ onIntersect: () => void;
+ disabled?: boolean;
+ threshold?: number;
+}
+
+export function useIntersection({
+ target,
+ onIntersect,
+ disabled,
+ threshold = 0.5,
+}: UseIntersectionProps) {
+ useEffect(() => {
+ if (disabled) return;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ if (entries[0].isIntersecting) {
+ onIntersect();
+ }
+ },
+ { threshold: threshold }
+ );
+
+ const current = target.current;
+ if (current) observer.observe(current);
+
+ return () => {
+ if (current) observer.unobserve(current);
+ observer.disconnect();
+ };
+ }, [target, onIntersect, disabled]);
+}