Skip to content

Commit

Permalink
Refactor: 무한스크롤 리팩토링 #65
Browse files Browse the repository at this point in the history
  • Loading branch information
jiyeeeah committed Oct 16, 2023
1 parent 6a7779f commit be00ae8
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 112 deletions.
4 changes: 1 addition & 3 deletions components/pages/main/Feed/BoardsList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ export default function BoardsList({
data: boardList,
isLoading,
hasNextPage,
} = useGetBoardList({
infiniteQueryKey: ['boards'],
});
} = useGetBoardList();

return (
<FlexBox direction="column" className="w-full gap-10">
Expand Down
46 changes: 46 additions & 0 deletions hooks/common/useInfiniteScroll.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

interface InfiniteScrollProps<T> {
queryKey: string;
firstPageParam: number;
queryFn: (pageNumber: number) => Promise<T>;
getNextPageParamFn: (page: T) => void;
}

export default function useInfiniteScroll<T>({
queryKey,
firstPageParam,
queryFn,
getNextPageParamFn,
}: InfiniteScrollProps<T>) {
const { data, fetchNextPage, isLoading, hasNextPage, isFetchingNextPage } =
useInfiniteQuery({
queryKey: [queryKey],
queryFn: ({ pageParam = firstPageParam }): Promise<T> =>
queryFn(pageParam),
getNextPageParam: getNextPageParamFn,
});

// 무한 스크롤 화면 가장 아래 부분 탐지하는 observer
function Observer({ children }: { children: React.ReactNode }) {
const { ref, inView } = useInView({ threshold: 1 });
useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [inView]);
if (!hasNextPage || !data) return null;
return (
<div ref={ref}>{isLoading || isFetchingNextPage ? children : null}</div>
);
}

return {
Observer,
data,
isLoading,
hasNextPage,
};
}
51 changes: 9 additions & 42 deletions hooks/queries/useGetBoardList.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,19 @@
'use client';

import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';
import { useInfiniteQuery } from '@tanstack/react-query';
import { getBoardList } from '@/service/board';
import { BoardList } from '@/types/types';
import useInfiniteScroll from '../common/useInfiniteScroll';

interface InfiniteScrollProps {
infiniteQueryKey: string[];
pageParameter?: number;
pageSize?: number;
inViewThreshold?: number;
}

export default function useGetBoardList({
infiniteQueryKey,
pageParameter = 1,
pageSize = 5,
}: InfiniteScrollProps) {
const { data, fetchNextPage, isLoading, hasNextPage, isFetchingNextPage } =
useInfiniteQuery({
queryKey: infiniteQueryKey,
queryFn: ({ pageParam = pageParameter }): Promise<BoardList> =>
getBoardList({ pageParam, pageSize }),
getNextPageParam: (boardlist) =>
boardlist.last ? undefined : boardlist.number + 1,
select: (d) => ({
pages: d.pages.flatMap((page) => page),
pageParams: d.pageParams,
}),
export default function useGetBoardList() {
const { data, isLoading, Observer, hasNextPage } =
useInfiniteScroll<BoardList>({
queryKey: 'boardsList',
firstPageParam: 0,
queryFn: getBoardList,
getNextPageParamFn: (boardList) =>
boardList.last ? undefined : boardList.number + 1,
});

// 무한 스크롤 화면 가장 아래 부분 탐지하는 observer
function Observer({ children }: { children: React.ReactNode }) {
const { ref, inView } = useInView({ threshold: 1 });

useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [inView]);

if (!hasNextPage || !data) return null;
return (
<div ref={ref}>{isLoading || isFetchingNextPage ? children : null}</div>
);
}

return {
Observer,
data,
Expand Down
41 changes: 8 additions & 33 deletions hooks/queries/useGetMyBoardList.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,17 @@
'use client';

import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';
import { useInfiniteQuery } from '@tanstack/react-query';
import getMyBoardList from '@/service/myPage';
import { MyBoardList } from '@/types/types';

const QUERY_KEY = ['myBoards'];
import useInfiniteScroll from '../common/useInfiniteScroll';

export default function useGetMyBoardList() {
const { data, fetchNextPage, isLoading, hasNextPage, isFetchingNextPage } =
useInfiniteQuery({
queryKey: QUERY_KEY,
queryFn: ({ pageParam = 0 }): Promise<MyBoardList> =>
getMyBoardList(pageParam),
getNextPageParam: (lastPage, allPages) =>
allPages.length < 20 ? allPages.length + 1 : undefined,
select: (d) => ({
pages: d.pages.flatMap((page) => page),
pageParams: d.pageParams,
}),
});

// 무한 스크롤 화면 가장 아래 부분 탐지하는 observer
function Observer({ children }: { children: React.ReactNode }) {
const { ref, inView } = useInView({ threshold: 1 });

useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [inView]);

if (!hasNextPage || !data) return null;
return (
<div ref={ref}>{isLoading || isFetchingNextPage ? children : null}</div>
);
}
const { data, isLoading, Observer } = useInfiniteScroll<MyBoardList>({
queryKey: 'myBoards',
firstPageParam: 0,
queryFn: getMyBoardList,
getNextPageParamFn: (boardlist) =>
boardlist.last ? undefined : boardlist.number + 1,
});

return {
Observer,
Expand Down
14 changes: 3 additions & 11 deletions hooks/queries/useGetMyBookmarkedBoardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,24 @@ import { useInfiniteQuery } from '@tanstack/react-query';
import getMyBoardList from '@/service/myPage';
import { BookmarkedBoardList } from '@/types/types';

const QUERY_KEY = ['bookmarkedBoards'];

export default function useGetBookmarkedBoardList() {
const { data, fetchNextPage, isLoading, hasNextPage, isFetchingNextPage } =
useInfiniteQuery({
queryKey: QUERY_KEY,
queryKey: ['bookmarkedBoards'],
queryFn: ({ pageParam = 0 }): Promise<BookmarkedBoardList> =>
getMyBoardList(pageParam),
getNextPageParam: (lastPage, allPages) =>
allPages.length < 20 ? allPages.length + 1 : undefined,
select: (d) => ({
pages: d.pages.flatMap((page) => page),
pageParams: d.pageParams,
}),
getNextPageParam: (boardlist) =>
boardlist.last ? undefined : boardlist.number + 1,
});

// 무한 스크롤 화면 가장 아래 부분 탐지하는 observer
function Observer({ children }: { children: React.ReactNode }) {
const { ref, inView } = useInView({ threshold: 1 });

useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [inView]);

if (!hasNextPage || !data) return null;
return (
<div ref={ref}>{isLoading || isFetchingNextPage ? children : null}</div>
Expand Down
31 changes: 8 additions & 23 deletions service/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ interface PostCommentType {
parentId: number;
content: string;
}
interface GetListApiProps {
pageParam: number;
pageSize: number;
}

export async function postBoard(postBoardData: PostBoardType) {
const url = `endpoint/api/board/register`;
Expand All @@ -29,10 +25,16 @@ export async function postBoard(postBoardData: PostBoardType) {
return response.json();
}

export async function getBoardList({ pageParam, pageSize }: GetListApiProps) {
export async function getBoardList(pageParam: number) {
let url = `/endpoint/api/board/list?pageSize=5`;
if (pageParam !== 0) {
url += `&pageNumber=${pageParam}`;
}
try {
const url = `/endpoint/api/board/list?pageNumber=${pageParam}&pageSize=${pageSize}`;
const response = await fetch(url);
if (response.status === 401) {
throw new AuthError('로그인이 필요한 서비스입니다.');
}
if (!response.ok) {
throw new Error(`서버오류:${response.status}`);
}
Expand All @@ -59,20 +61,3 @@ export async function postComment(postCommentData: PostCommentType) {
});
return response.json();
}

// export async function getCommentList({ pageParam, pageSize }: GetListApiProps) {
// try {
// const url = `/endpoint/api/reply/list?pageNumber=${pageParam}&pageSize=${pageSize}`;
// const response = await fetch(url);
// if (!response.ok) {
// throw new Error(`서버오류:${response.status}`);
// }
// return await response.json();
// } catch (error) {
// if (error instanceof AuthError) {
// window.location.replace('/auth/login');
// alert(error.message);
// }
// throw error;
// }
// }

0 comments on commit be00ae8

Please sign in to comment.