-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 메인페이지 api연동 #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,41 @@ | ||
| import { serverApi } from "@/lib/server-api"; | ||
| import { | ||
| dehydrate, | ||
| HydrationBoundary, | ||
| QueryClient, | ||
| } from "@tanstack/react-query"; | ||
| import React from "react"; | ||
| import ScreenMainPage from "./_components/ScreenMainPage"; | ||
|
|
||
| export default function MainPage() { | ||
| return <ScreenMainPage />; | ||
| import { ItemsResponse } from "@/hooks/useItems"; | ||
| import { MatchingHistoryResponse } from "@/hooks/useMatchingHistory"; | ||
|
|
||
| export default async function MainPage() { | ||
| const queryClient = new QueryClient(); | ||
|
|
||
| // 서버사이드에서 데이터를 미리 가져와서 캐시에 채워줍니다. | ||
| await Promise.all([ | ||
| queryClient.prefetchQuery({ | ||
| queryKey: ["items"], | ||
| queryFn: async () => { | ||
| const res = await serverApi.get<ItemsResponse>({ path: "/api/items" }); | ||
| return res.data; | ||
| }, | ||
| }), | ||
| queryClient.prefetchQuery({ | ||
| queryKey: ["matchingHistory"], | ||
| queryFn: async () => { | ||
| const res = await serverApi.get<MatchingHistoryResponse>({ | ||
| path: "/api/matching/history", | ||
| }); | ||
| return res.data; | ||
| }, | ||
| }), | ||
| ]); | ||
|
Comment on lines
+16
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. Ssr prefetch crashes page In app/main/page.tsx, the server component awaits Promise.all of two prefetchQuery calls without any error handling, so if either /api/items or /api/matching/history fails the whole page render throws and returns a 500. This defeats the client components’ graceful loading/error behavior because the page never renders to the point where React Query can handle it on the client. Agent Prompt
|
||
|
|
||
| return ( | ||
| <HydrationBoundary state={dehydrate(queryClient)}> | ||
| <ScreenMainPage /> | ||
| </HydrationBoundary> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { api } from "@/lib/axios"; | ||
| import { useQuery } from "@tanstack/react-query"; | ||
|
|
||
| interface Item { | ||
| itemId: number; | ||
| itemType: string; | ||
| quantity: number; | ||
| expiredAt: string; | ||
| } | ||
|
|
||
| export interface ItemsResponse { | ||
| code: string; | ||
| status: number; | ||
| message: string; | ||
| data: { | ||
| items: { | ||
| content: Item[]; | ||
| currentPage: number; | ||
| size: number; | ||
| totalElements: number; | ||
| totalPages: number; | ||
| hasNext: boolean; | ||
| hasPrevious: boolean; | ||
| }; | ||
| matchingTicketCount: number; | ||
| optionTicketCount: number; | ||
| }; | ||
| } | ||
|
|
||
| export const fetchItems = async (): Promise<ItemsResponse> => { | ||
| const { data } = await api.get<ItemsResponse>("/api/items"); | ||
| return data; | ||
| }; | ||
|
|
||
| export const useItems = () => { | ||
| return useQuery({ | ||
| queryKey: ["items"], | ||
| queryFn: fetchItems, | ||
| staleTime: Infinity, // 충전/소모 전까지는 데이터가 변하지 않으므로 무한정 캐싱 | ||
| gcTime: 1000 * 60 * 60, // 메모리에서 1시간 동안 유지 | ||
| }); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import { api } from "@/lib/axios"; | ||
| import { | ||
| Gender, | ||
| MBTI, | ||
| SocialType, | ||
| Hobby, | ||
| IntroItem, | ||
| ContactFrequency, | ||
| } from "@/lib/types/profile"; | ||
| import { useQuery } from "@tanstack/react-query"; | ||
|
|
||
| export interface MatchingPartner { | ||
| memberId: number; | ||
| email: string; | ||
| nickname: string; | ||
| gender: Gender; | ||
| birthDate: string; | ||
| mbti: MBTI; | ||
| intro: string | null; | ||
| profileImageUrl: string; | ||
| socialType: SocialType | null; | ||
| socialAccountId: string | null; | ||
| university: string; | ||
| major: string; | ||
| contactFrequency: ContactFrequency; | ||
| hobbies: Hobby[]; | ||
| intros: IntroItem[]; | ||
| advantages: string[] | null; | ||
| favoriteSong: string | null; | ||
| } | ||
|
|
||
| export interface MatchingHistoryItem { | ||
| historyId: number; | ||
| partner: MatchingPartner; | ||
| favorite: boolean; | ||
| matchedAt: string; | ||
| } | ||
|
|
||
| export interface MatchingHistoryResponse { | ||
| code: string; | ||
| status: number; | ||
| message: string; | ||
| data: { | ||
| content: MatchingHistoryItem[]; | ||
| currentPage: number; | ||
| size: number; | ||
| totalElements: number; | ||
| totalPages: number; | ||
| hasNext: boolean; | ||
| hasPrevious: boolean; | ||
| }; | ||
| } | ||
|
|
||
| export const fetchMatchingHistory = | ||
| async (): Promise<MatchingHistoryResponse> => { | ||
| const { data } = await api.get<MatchingHistoryResponse>( | ||
| "/api/matching/history", | ||
| ); | ||
| return data; | ||
| }; | ||
|
Comment on lines
+54
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
export const fetchMatchingHistory = async (): Promise<MatchingHistoryResponse> => {
const { data } = await api.get<MatchingHistoryResponse>(
"/api/matching/history",
);
return data;
};References
|
||
|
|
||
| export const useMatchingHistory = () => { | ||
| return useQuery({ | ||
| queryKey: ["matchingHistory"], | ||
| queryFn: fetchMatchingHistory, | ||
| staleTime: Infinity, // 새로운 매칭이나 즐겨찾기 변경 전까지는 캐시 유지 | ||
| gcTime: 1000 * 60 * 60, // 메모리에서 1시간 동안 유지 | ||
| }); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API 응답 데이터를 UI 모델(
ProfileData)로 변환하는 로직을 더 간결하고 효율적으로 개선할 수 있습니다.contactFrequency를 변환하는 3항 연산자 체인 대신, 가독성 높은 매핑 객체를 사용하면 의도를 명확히 할 수 있습니다. 이 매핑 객체를map콜백 바깥에 선언하면 렌더링 시마다 객체가 불필요하게 재생성되는 것을 방지할 수 있습니다....item.partner스프레드 연산으로 대부분의 속성이 이미 복사되므로, 불필요한 재할당을 제거하여 코드를 간결하게 만들 수 있습니다.아래와 같이 수정하면 코드가 더 깔끔해지고 성능적으로도 미세하게나마 이점이 있습니다.
References
mapcallback aligns with improving separation of concerns and efficiency for data transformation.