diff --git a/src/app/(routes)/member/[memberId]/character-create-link.tsx b/src/app/(routes)/member/[memberId]/character-create-link.tsx
deleted file mode 100644
index 18fdd80..0000000
--- a/src/app/(routes)/member/[memberId]/character-create-link.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import Link from 'next/link';
-
-export default function CharacterCreateLink() {
- return (
-
- 내 캐릭터 만들러 가기
-
- );
-}
diff --git a/src/app/(routes)/member/[memberId]/characters-container.tsx b/src/app/(routes)/member/[memberId]/characters-container.tsx
new file mode 100644
index 0000000..1834371
--- /dev/null
+++ b/src/app/(routes)/member/[memberId]/characters-container.tsx
@@ -0,0 +1,34 @@
+'use client';
+
+import FixedBottomArea from '@/components/fixed-bottom-area';
+import CTAButton from '@/components/ui/cta-button';
+import { Member } from '@/services/auth/getMember';
+import { useCharactersQuery } from '@/store/query/useCharactersQuery';
+import { Characters } from './characters';
+import { Header } from './header';
+import { MemberData } from './member-data';
+
+type Props = {
+ memberId: Member['memberId'];
+};
+
+export function CharactersContainer({ memberId }: Props) {
+ const {
+ data: { characters, cheerCount, memberNickname, isMe, joinDays, memoCount },
+ } = useCharactersQuery(memberId);
+
+ const isMyPage = isMe;
+
+ return (
+ <>
+
+
+
+
+
+ {!isMyPage && (
+ } />
+ )}
+ >
+ );
+}
diff --git a/src/app/(routes)/member/[memberId]/characters.tsx b/src/app/(routes)/member/[memberId]/characters.tsx
new file mode 100644
index 0000000..74ed632
--- /dev/null
+++ b/src/app/(routes)/member/[memberId]/characters.tsx
@@ -0,0 +1,36 @@
+import { GetCharactersResponse } from '@/services/character/getCharacters';
+import CharacterCard from './character-card';
+import CharacterCreateButton from './character-create-button';
+
+type Props = {
+ isMyPage: boolean;
+ characters: GetCharactersResponse['characters'];
+};
+
+const MAXIMUM_CHARACTER = 6;
+
+export function Characters({ characters, isMyPage }: Props) {
+ const showCharacterCreateButton = isMyPage && characters.length < MAXIMUM_CHARACTER;
+
+ return (
+
+ 성장 기록지
+
+ {characters?.map((character, i) => {
+ if (isMyPage)
+ return (
+
+ );
+ return ;
+ })}
+ {showCharacterCreateButton && }
+
+
+ );
+}
diff --git a/src/app/(routes)/member/[memberId]/header.tsx b/src/app/(routes)/member/[memberId]/header.tsx
new file mode 100644
index 0000000..785c2cb
--- /dev/null
+++ b/src/app/(routes)/member/[memberId]/header.tsx
@@ -0,0 +1,20 @@
+import { LikeButton, LikeButtonWithTooltip } from './like-button';
+import { GetCharactersResponse } from '@/services/character/getCharacters';
+
+type Props = {
+ isMyPage: boolean;
+} & Pick;
+
+export function Header({ isMyPage, memberNickname, cheerCount }: Props) {
+ const headerText = `${memberNickname}의 도감 `;
+ return (
+
+ {headerText}
+ {isMyPage ? (
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/src/app/(routes)/member/[memberId]/member-data.tsx b/src/app/(routes)/member/[memberId]/member-data.tsx
new file mode 100644
index 0000000..2ad6941
--- /dev/null
+++ b/src/app/(routes)/member/[memberId]/member-data.tsx
@@ -0,0 +1,49 @@
+import EggImage from '@/assets/images/egg.png';
+import PencilImage from '@/assets/images/pencil.png';
+import { GetCharactersResponse } from '@/services/character/getCharacters';
+import Image from 'next/image';
+
+type Props = Pick;
+export function MemberData({ joinDays, memoCount }: Props) {
+ return (
+
+ );
+}
diff --git a/src/app/(routes)/member/[memberId]/page.tsx b/src/app/(routes)/member/[memberId]/page.tsx
index 154bc34..6f59657 100644
--- a/src/app/(routes)/member/[memberId]/page.tsx
+++ b/src/app/(routes)/member/[memberId]/page.tsx
@@ -1,112 +1,22 @@
-import EggImage from '@/assets/images/egg.png';
-import PencilImage from '@/assets/images/pencil.png';
-import { PageContainer } from '@/components/ui';
import A2HS from '@/hooks/useA2HS';
-import getMember from '@/services/auth/getMember';
-import getCharacters from '@/services/character/getCharacters';
import { cookies } from 'next/headers';
-import Image from 'next/image';
-import CharacterCard from './character-card';
-import CharacterCreateButton from './character-create-button';
-import CharacterCreateLink from './character-create-link';
-import { LikeButton, LikeButtonWithTooltip } from './like-button';
import PageContainerV2 from '@/components/page-container-v2/page-container-v2';
+import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query';
+import { charactersQueryOptions } from '@/store/query/useCharactersQuery';
+import { CharactersContainer } from './characters-container';
-const MAXIMUM_CHARACTER = 6;
+export default async function Home({ params: { memberId } }: { params: { memberId: number } }) {
+ const accessToken = `${cookies().get('accessToken')?.value}`;
-export default async function Home({ params: { memberId } }: { params: { memberId: string } }) {
- const accessToken = cookies().get('accessToken')?.value;
-
- const characters = await getCharacters({
- memberId: Number(memberId),
- accessToken,
- });
-
- const isMyPage = characters?.isMe;
- const headerText = `${characters?.memberNickname}의 도감 `;
- const showCharacterCreateButton = isMyPage && characters.characters.length < MAXIMUM_CHARACTER;
+ const queryClient = new QueryClient();
+ const { isMe } = await queryClient.fetchQuery(charactersQueryOptions(accessToken, memberId));
return (
-
-
-
- {headerText}
- {isMyPage ? (
-
- ) : (
-
- )}
-
-
- 성장과정
-
-
-
-
성장한지
-
- {characters?.joinDays}일
-
-
-
-
-
-
-
-
-
총 메모
-
- {characters?.memoCount}개
-
-
-
-
-
-
-
-
-
- 성장 기록지
-
- {characters?.characters?.map((character, i) => {
- if (isMyPage)
- return (
-
- );
- return ;
- })}
- {showCharacterCreateButton && }
-
-
-
-
- {!isMyPage && (
-
-
-
- )}
-
-
+
+
+
+
+
+
);
}
diff --git a/src/services/character/getCharacters.ts b/src/services/character/getCharacters.ts
index a6b8518..bd6ccd4 100644
--- a/src/services/character/getCharacters.ts
+++ b/src/services/character/getCharacters.ts
@@ -15,7 +15,7 @@ export type GetCharactersRequest = {
accessToken?: string;
};
-export default async function getCharacters(request: GetCharactersRequest): Promise {
+export default async function getCharacters(request: GetCharactersRequest): Promise {
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_BASE_URL}/api/v1/character/member/${request.memberId}`,
diff --git a/src/store/query/useCharactersQuery.ts b/src/store/query/useCharactersQuery.ts
new file mode 100644
index 0000000..94547db
--- /dev/null
+++ b/src/store/query/useCharactersQuery.ts
@@ -0,0 +1,19 @@
+import { Member } from '@/services/auth/getMember';
+import getCharacters, { GetCharactersResponse } from '@/services/character/getCharacters';
+import { BasicSuspenseQueryOptions } from '@/types/query';
+import { useSuspenseQuery } from '@tanstack/react-query';
+import { getCookie } from 'cookies-next';
+
+export const charactersQueryOptions = (
+ accessToken: string,
+ memberId: Member['memberId'],
+): BasicSuspenseQueryOptions => ({
+ queryKey: ['characters', memberId],
+ queryFn: () => getCharacters({ memberId, accessToken }),
+});
+
+export function useCharactersQuery(memberId: Member['memberId']) {
+ return useSuspenseQuery({
+ ...charactersQueryOptions(`${getCookie('accessToken')}`, memberId),
+ });
+}