Skip to content

Commit

Permalink
feat: 전체 방 조회 API 연결 및 기능 구현 (#164)
Browse files Browse the repository at this point in the history
* feat: 전체 방 조회 msw API 및 쿼리 작성

* feat: 방 전체 조회 API 연결

* feat: 옵저버 제외한 무한 fetching 기능 추가

* feat: 로딩 fallback 추가

* feat: 무한스크롤 쿼리 로직 분리

* feat: 무한스크롤 커스텀 훅 구현 및 기능 연결

* feat: 옵저버 훅 및 UI 수정

* feat: 코드 리뷰 반영
  • Loading branch information
chasj0326 authored Nov 18, 2023
1 parent 5768a3d commit e4224aa
Show file tree
Hide file tree
Showing 14 changed files with 993 additions and 18 deletions.
50 changes: 41 additions & 9 deletions src/RoomSearch/components/ResultList.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,51 @@
import { Room } from '@/RoomList/mocks/types/rooms';
import { RoomSelectType } from '@/core/types';
import { useInfiniteSearch } from '@/core/api/queries';
import useIntersectionObserver from '../hooks/useIntersectionObserver';
import ResultListFallback from './ResultListFallback';
import { RoomAccordion } from '@/RoomList';
import { Deffered } from '@/shared/Deffered';

interface ResultListProps {
rooms: Room[];
type: RoomSelectType;
size: number;
}

const ResultList = ({ rooms }: ResultListProps) => {
const ResultList = ({ type, size }: ResultListProps) => {
const { fetchNextPage, data, isFetchingNextPage, hasNextPage } =
useInfiniteSearch({
type,
size
});
const intersectionRef = useIntersectionObserver({
threshold: 0.5,
onObserve: fetchNextPage
});

return (
<div className="flex flex-col gap-2">
{rooms.map((room) => (
<RoomAccordion
room={room}
key={room.id}
/>
))}
{data.map((rooms) =>
rooms.map((room) => (
<RoomAccordion
room={room}
key={room.id}
/>
))
)}
{isFetchingNextPage && (
<Deffered>
<ResultListFallback size={size} />
</Deffered>
)}
{hasNextPage ? (
<div
ref={intersectionRef}
className="h-4"
></div>
) : (
<div className="my-4 text-center text-sm text-dark-gray">
모든 방을 다 불러왔어요.
</div>
)}
</div>
);
};
Expand Down
20 changes: 20 additions & 0 deletions src/RoomSearch/components/ResultListFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';

interface ResultListFallbackProps {
size?: number;
}

const ResultListFallback = ({ size = 10 }: ResultListFallbackProps) => {
return (
<div className="flex flex-col gap-2 opacity-60">
{Array.from({ length: size }, (_, index) => (
<div
key={index}
className="my-1 h-24 w-full animate-pulse rounded-2xl bg-light-gray dark:bg-dark-gray"
></div>
))}
</div>
);
};

export default ResultListFallback;
41 changes: 41 additions & 0 deletions src/RoomSearch/hooks/useIntersectionObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useCallback, useEffect, useRef } from 'react';

interface ObserverOptions {
root?: Element | null;
rootMargin?: string;
threshold?: number;
onObserve: VoidFunction;
}

const useIntersectionObserver = ({
onObserve,
...options
}: ObserverOptions) => {
const intersectionRef = useRef<HTMLDivElement>(null);

const handleIntersect: IntersectionObserverCallback = useCallback(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
onObserve();
}
});
},
[onObserve]
);

useEffect(() => {
const observer = new IntersectionObserver(handleIntersect, options);
const intersectionElement = intersectionRef.current;

intersectionElement && observer.observe(intersectionElement);

return () => {
intersectionElement && observer.unobserve(intersectionElement);
};
}, [handleIntersect, options]);

return intersectionRef;
};

export default useIntersectionObserver;
2 changes: 1 addition & 1 deletion src/core/api/functions/couponAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CouponStatus } from '@/core/types';
import { baseInstance } from '../instance';

const couponAPI = {
postAllCoupons: async (body: CouponStatus) => {
postCouponsByStatus: async (body: CouponStatus) => {
return await baseInstance.post<Coupons>('/coupons/search', body);
}
};
Expand Down
6 changes: 6 additions & 0 deletions src/core/api/functions/roomAPI.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RoomsRequestParams, TotalRooms } from '@/core/types';
import { baseInstance } from '../instance';
import { MyJoinRoom } from '@/core/types/MyJoinRoom';
import { RoomInfo } from '@/core/types/Room';
Expand Down Expand Up @@ -49,6 +50,11 @@ const roomAPI = {
return await baseInstance.put(
`/rooms/${roomId}/members/${memberId}/delegation`
);
},

getRoomsAll: async (params?: RoomsRequestParams) => {
const response: TotalRooms = await baseInstance.get('/rooms', { params });
return response.rooms;
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/core/api/options/coupon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const couponOptions = {
all: (body: CouponStatus) =>
queryOptions({
queryKey: ['coupons', body] as const,
queryFn: () => couponAPI.postAllCoupons(body)
queryFn: () => couponAPI.postCouponsByStatus(body)
})
};

Expand Down
7 changes: 7 additions & 0 deletions src/core/api/options/room.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { queryOptions } from '@tanstack/react-query';
import { RoomsRequestParams } from '@/core/types';
import roomAPI from '../functions/roomAPI';

const roomOptions = {
Expand All @@ -12,6 +13,12 @@ const roomOptions = {
queryOptions({
queryKey: ['rooms', 'myJoin'] as const,
queryFn: () => roomAPI.getMyJoinRoom()
}),

all: (params?: RoomsRequestParams) =>
queryOptions({
queryKey: ['rooms', params?.type || 'all'] as const,
queryFn: () => roomAPI.getRoomsAll(params)
})
};

Expand Down
1 change: 1 addition & 0 deletions src/core/api/queries/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as useInfiniteSearch } from './useInfiniteSearch';
27 changes: 27 additions & 0 deletions src/core/api/queries/useInfiniteSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useSuspenseInfiniteQuery } from '@tanstack/react-query';
import { RoomSelectType } from '@/core/types';
import roomAPI from '../functions/roomAPI';

const useInfiniteSearch = ({
type,
size
}: {
type: RoomSelectType;
size: number;
}) => {
return useSuspenseInfiniteQuery({
queryKey: ['rooms', type],

queryFn: ({ pageParam }) =>
roomAPI.getRoomsAll({ page: pageParam, type, size }),

initialPageParam: 1,

getNextPageParam: (lastPage, allPages, lastPageParam) =>
lastPage.length < size ? null : lastPageParam + 1,

select: ({ pages }) => pages
});
};

export default useInfiniteSearch;
Loading

0 comments on commit e4224aa

Please sign in to comment.