Skip to content

Commit 9f10236

Browse files
committed
Feat: 페이지네이션 merge 이후 Link 페이지 개선, useViewport useFetchLinks 훅 추가
2 parents 866a0f4 + b804a55 commit 9f10236

File tree

7 files changed

+77
-28
lines changed

7 files changed

+77
-28
lines changed

components/Link/AddLinkInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ChangeEvent, KeyboardEvent, useState } from "react";
1+
import { ChangeEvent, KeyboardEvent, useEffect, useState } from "react";
22
import { FolderListData } from "@/types/folderTypes";
33
import { Modal } from "../modal/modalManager/ModalManager";
44
import Image from "next/image";

components/Link/LinkCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ interface LinkCardProps {
2222
const LinkCard = ({ openEdit, openDelete, info }: LinkCardProps) => {
2323
const [isSubscribed, setIsSubscribed] = useState(false);
2424
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
25-
const { isOpen: isModalOpen } = useModalStore(); // 모달 열림 상태 구독
25+
const { isOpen: isModalOpen } = useModalStore();
2626

2727
const formattedDate = info.createdAt?.slice(0, 10).replace(/-/g, ".");
2828
const createdTime = timeAgo(info.createdAt);

hooks/useFetchLinks.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
import { useEffect } from "react";
22
import { proxy } from "@/lib/api/axiosInstanceApi";
33
import { LinkData } from "@/types/linkTypes";
4+
import useViewport from "./useViewport";
45

5-
// 검색어에 맞는 리스트로 setLinkCardList 해주는 함수
6+
// 링크페이지의 query가 바뀌면 새로운 리스트로 업데이트 해주는
67
const useFetchLinks = (
7-
search: string | string[] | undefined,
8+
query: {
9+
page?: number;
10+
search?: string;
11+
},
812
setLinkCardList: (list: LinkData[]) => void
913
) => {
14+
const { isTablet } = useViewport();
15+
1016
useEffect(() => {
1117
const fetchLinks = async () => {
12-
const res = await proxy.get("/api/links", { params: { search } });
18+
const res = await proxy.get("/api/links", {
19+
params: {
20+
page: query.page,
21+
pageSize: isTablet ? 6 : 10,
22+
search: query.search,
23+
},
24+
});
1325
setLinkCardList(res.data.list);
1426
};
15-
if (search) fetchLinks();
16-
}, [search, setLinkCardList]);
27+
28+
if (query) fetchLinks();
29+
}, [query, setLinkCardList, isTablet]);
1730
};
1831

1932
export default useFetchLinks;

hooks/useViewport.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useState, useEffect } from "react";
2+
3+
const breakpoints = {
4+
PC: { min: 1200 },
5+
Tablet: { min: 768, max: 1199 },
6+
Mobile: { min: 343, max: 767 },
7+
};
8+
9+
// 현재 브라우저의 innerWidth와 반응형 상태를 반환하는 훅
10+
function useViewport(initialWidth = 0) {
11+
const [width, setWidth] = useState(initialWidth);
12+
13+
const handleResize = () => {
14+
setWidth(window.innerWidth);
15+
};
16+
17+
useEffect(() => {
18+
handleResize();
19+
window.addEventListener("resize", handleResize);
20+
return () => window.removeEventListener("resize", handleResize);
21+
}, []);
22+
23+
const isPC = width >= breakpoints.PC.min;
24+
const isTablet =
25+
width >= breakpoints.Tablet.min && width <= breakpoints.Tablet.max;
26+
const isMobile =
27+
width >= breakpoints.Mobile.min && width <= breakpoints.Mobile.max;
28+
29+
return { width, isPC, isTablet, isMobile };
30+
}
31+
32+
export default useViewport;

pages/api/links/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import axiosInstance from "@/lib/api/axiosInstanceApi";
55
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
66
const cookies = parse(req.headers.cookie || "");
77
const accessToken = cookies.accessToken;
8-
const { page, search } = req.query;
8+
const { page, pageSize, search } = req.query;
99

1010
switch (req.method) {
1111
case "GET":
1212
// 유저의 전체 링크 조회
1313
try {
14-
const response = await axiosInstance.get("/links", {
15-
params: { page, search },
14+
const response = await axiosInstance.get(`/links`, {
15+
params: { page, pageSize, search },
1616
headers: { Authorization: `Bearer ${accessToken}` },
1717
});
1818
return res.status(201).json(response.data);

pages/link/index.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,57 @@ import { FolderData } from "@/types/folderTypes";
66
import { Modal } from "@/components/modal/modalManager/ModalManager";
77
import { useLinkCardStore } from "@/store/useLinkCardStore";
88
import { SearchInput } from "../../components/Search/SearchInput";
9-
import fetchProxy from "@/lib/api/fetchProxy";
109
import useModalStore from "@/store/useModalStore";
10+
import Pagination from "@/components/Pagination";
1111
import useFetchLinks from "@/hooks/useFetchLinks";
12-
import CardsLayout from "@/components/Layout/CardsLayout";
13-
import Container from "@/components/Layout/Container";
14-
import FolderActionsMenu from "@/components/Folder/FolderActionsMenu";
1512
import AddLinkInput from "@/components/Link/AddLinkInput";
13+
import Container from "@/components/Layout/Container";
1614
import SearchResultMessage from "@/components/Search/SearchResultMessage";
17-
import LinkCard from "@/components/Link/LinkCard";
15+
import FolderTag from "@/components/Folder/FolderTag";
1816
import AddFolderButton from "@/components/Folder/AddFolderButton";
19-
import FolderTag from "../../components/Folder/FolderTag";
17+
import FolderActionsMenu from "@/components/Folder/FolderActionsMenu";
18+
import CardsLayout from "@/components/Layout/CardsLayout";
19+
import LinkCard from "@/components/Link/LinkCard";
20+
import fetchProxy from "@/lib/api/fetchProxy";
2021

2122
interface LinkPageProps {
2223
linkList: LinkData[];
2324
folderList: FolderData[];
25+
totalCount: number;
2426
}
2527

2628
// /link 페이지 접속시에 초기렌더링 데이터(전체 폴더, 전체링크리스트)만 fetch해서 client로 전달.
2729
export const getServerSideProps = async (
2830
context: GetServerSidePropsContext
2931
) => {
32+
const { req } = context;
33+
3034
const [links, folders] = await Promise.all([
31-
fetchProxy("/api/links", context.req),
32-
fetchProxy("/api/folders", context.req),
35+
fetchProxy("/api/links", req),
36+
fetchProxy("/api/folders", req),
3337
]);
3438

3539
return {
3640
props: {
3741
linkList: links.list || [],
3842
folderList: folders || [],
43+
totalCount: links.totalCount || 0,
3944
},
4045
};
4146
};
4247

4348
const LinkPage = ({
4449
linkList: initialLinkList,
4550
folderList: initialFolderList,
51+
totalCount,
4652
}: LinkPageProps) => {
4753
const router = useRouter();
4854
const { search } = router.query;
4955
const { isOpen, openModal } = useModalStore();
5056
const { linkCardList, setLinkCardList } = useLinkCardStore();
5157
const [folderList, setFolderList] = useState(initialFolderList);
5258

53-
useFetchLinks(search, setLinkCardList);
59+
useFetchLinks(router.query, setLinkCardList);
5460

5561
// 클라이언트에서 초기 목록을 설정
5662
useEffect(() => {
@@ -94,6 +100,7 @@ const LinkPage = ({
94100
/>
95101
))}
96102
</CardsLayout>
103+
<Pagination totalCount={totalCount} />
97104
</Container>
98105
{isOpen && <Modal />}
99106
</main>

store/useLinkCardStore.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
import { deleteLinkURL, getLinks, putLinkURL } from "@/lib/api/link";
22
import { create } from "zustand";
3-
import { LinkData } from "@/types/linkTypes";
43

54
interface UpdateLinkBody {
65
url: string;
76
}
87

98
interface LinkCardStore {
10-
linkCardList: LinkData[];
11-
totalCount: number;
12-
setLinkCardList: (list: LinkData[]) => void;
9+
linkCardList: LinkCardDataType[];
10+
setLinkCardList: (list: LinkCardDataType[]) => void;
1311
updateLink: (linkId: number, body: UpdateLinkBody) => Promise<void>;
1412
deleteLink: (linkId: number) => Promise<void>;
1513
}
1614

1715
export const useLinkCardStore = create<LinkCardStore>((set) => ({
1816
linkCardList: [],
19-
totalCount: 0,
2017

21-
setLinkCardList: (list: LinkData[]) => {
22-
set({ linkCardList: list, totalCount: list.length });
18+
setLinkCardList: (list: LinkCardDataType[]) => {
19+
set({ linkCardList: list });
2320
},
2421

2522
// 수정 요청 보낸 후 목록 가져오기
@@ -31,7 +28,7 @@ export const useLinkCardStore = create<LinkCardStore>((set) => ({
3128
const updatedList = res.list;
3229

3330
// 상태 업데이트
34-
set({ linkCardList: updatedList, totalCount: updatedList.length });
31+
set({ linkCardList: updatedList });
3532
} catch (error) {
3633
console.error("삭제 중 오류 발생:", error);
3734
}
@@ -45,7 +42,7 @@ export const useLinkCardStore = create<LinkCardStore>((set) => ({
4542
const updatedList = res.list;
4643

4744
// 상태 업데이트
48-
set({ linkCardList: updatedList, totalCount: updatedList.length });
45+
set({ linkCardList: updatedList });
4946
} catch (error) {
5047
console.error("삭제 중 오류 발생:", error);
5148
}

0 commit comments

Comments
 (0)