๋ฐฐ๊ฒฝ
๋งค์ฐ ๋๋ฆฌ๋ ์๊ธฐ์๊ฐ์ ํ์ด์ง์ ๋ก๋ฉ ์๋๋ฅผ ๊ฐ์ ํ ์ฌ๋ก๋ฅผ ์๊ฐํ๊ณ ์ ํ๋ค.
Next.js์ parallel route๋ฅผ ์ฌ์ฉํ์ฌ ํ์ด์ง ๋ก๋ฉ ์๋๋ฅผ ์ฝ 94% ๊ฐ์ ํ ๋ด์ฉ์ ๊ณต์ ํ๋ค.
์ธ์ฌ์ดํธ์์์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํด ์๊ธฐ์๊ฐ์ ์์ฑ ํ์ด์ง๋ฅผ ์ ์ํ๋ฉด ๊ฐ์ฅ ์ต๊ทผ์ ์์ฑํ๋ ์๊ธฐ์๊ฐ์๋ฅผ ๋ณด์ฌ์ค๋ค.
์ด ํ์ด์ง๋ฅผ ์ ์ํ๊ธฐ๊น์ง๋ ์ฝ 10์ด๊ฐ ๊ฑธ๋ฆฌ๋ ์น๋ช ์ ์ธ ๋ฌธ์ ์ ์ด ์์๋ค.
์์ธ
๋ฌธ์ ์ ์์ธ์ ์๊ธฐ์๊ฐ์ ์์ฑ ๋ผ์ฐํ ๋ฐฉ์๋๋ฌธ์ด์๋ค.
์๊ธฐ์๊ฐ์ ์์ฑํ๊ธฐ ๋ฉ๋ด๋ฅผ ํด๋ฆญํ๋ฉด /resumes/${questionId}
๋ก ์ด๋ํ๋ค.
questionId๋ ๊ฐ์ฅ ์ต๊ทผ์ ์์ฑํ๋ ์๊ธฐ์๊ฐ์๋ก, ์๊ธฐ์๊ฐ์ ๋ชฉ๋ก ์กฐํ API ์กฐํ ํ ๊ฐ์ฅ ์ฒซ๋ฒ์งธ ์๊ธฐ์๊ฐ์ ์ง๋ฌธ ํญ๋ชฉ์ด questionId์ด๋ค.
์๊ธฐ์๊ฐ์ ๋ ์ด์์์ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์์๋ค.
// app/resumes/layout.tsx
const Layout = ({ children }: PropsWithChildren) => {
return (
<>
<Aside />
<ResumeForm />
<MyExperienceCard />
</>
);
};
์๊ธฐ์๊ฐ์ ๋ชฉ๋ก ์กฐํ API ์กฐํ -> ๊ฐ์ฅ ์ฒซ๋ฒ์งธ ์๊ธฐ์๊ฐ์ ์ง๋ฌธ ํญ๋ชฉ์ questionId๋ฅผ ์ฐพ๊ธฐ ์ ๊น์ง๋ ์๊ธฐ์๊ฐ์ ๋ฟ๋ง ์๋๋ผ ์๊ธฐ์๊ฐ์ ๋ชฉ๋ก Aside
, ์๊ธฐ์๊ฐ์์๋ ๋ฌด๊ดํ ๋ด ๊ฒฝํ์นด๋
๊น์ง ๋ณผ ์ ์๋ ํ์์ด ๋ฐ์ํ๋ค.
๋ฌธ์ ํด๊ฒฐ: Parallel Routes
Next.js์์ ๋์ผํ ๋ ์ด์์์์ ์ฌ๋ฌ๊ฐ์ ํ์ด์ง๋ฅผ ๋ ๋๋ง์ ๋์์ ํ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ์ด๋ค.
์๋ ์ด๋ฏธ์ง๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋ ์ง๊ด์ ์ผ๋ก ์ดํดํ ์ ์๋ค.
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes
์ด ๋ฐฉ์์ ์ด์ฉํด์ ์๊ธฐ์๊ฐ์ ์์ฑ ํ์ด์ง์์ Aside(ํํฌ), ResumeForm(๋ น์), MyExperienceCard(ํ๋)์ "๋ณ๋ ฌ์ "์ผ๋ก ๋ ๋๋งํ ์ ์๋ค.
Parallel Route๋ฅผ ๋์ ํ๊ธฐ ์ด์
ํ๋์ layout์์ ์ฌ๋ฌ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์๋ค.
// app/resumes/layout.tsx
const Layout = ({ children }: PropsWithChildren) => {
return (
<>
<Aside />
<ResumeForm />
<MyExperienceCard />
</>
);
};
๊ฐ ์ปดํฌ๋ํธ์ ๋ก๋ฉ ์ํ์ ์๋ฌ ์ํ๋ฅผ ํ์ด์ง ์ ์ญ์ผ๋ก ๊ด๋ฆฌ๋๋ค.
์๋ฅผ ๋ค์ด, Aside์์๋ง ์๋ฌ๊ฐ ๋ฐ์ํ๋๋ผ๋ ํ์ด์ง ์ ์ฒด์ ์๋ฌ๋ก ์ ํ๋๋ค.
Parallel Route ๋์
@๋ก ์์ํ๋ ํด๋ ์ปจ๋ฒค์
์ ๊ฐ๊ณ ์์ด์, @ํด๋์ด๋ฆ
๋ด๋ถ์ page.js๋ฅผ ๋ง๋ค์ด์ฃผ๋ฉด Parallel Routing ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.
Parallel Routing์ ๊ฐ๊ฐ์ ์๋ฌ์ ๋ก๋ฉ ์ํ๋ฅผ ์ ์ํ ์ ์๋ค.
@ํด๋์ด๋ฆ
๋ด๋ถ์ Next.js๊ฐ ์ปจ๋ฒค์
์ผ๋ก ์ฌ์ฉํ๊ณ ์๋ loading.js, error.js๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๋ค.
@ํด๋์ด๋ฆ ์ปจ๋ฒค์ ์ผ๋ก ์ ํด์ง slot์ ๊ฐ์ ๋ ๋ฒจ์ ๋ ์ด์์์ props๋ก ์ ๋ฌ๋๋ค.
์ฆ, @aside
, @myExperienceCard
๊ฐ resumes/layout.tsx
์ props๋ก ์ ๋ฌ๋๋ค.
import { PropsWithChildren, ReactNode } from 'react';
type LayoutProps = PropsWithChildren & {
aside: ReactNode;
myExperienceCard: ReactNode;
};
const Layout = ({ children, aside, myExperienceCard }: LayoutProps) => {
return (
<Container>
{aside}
{children}
{myExperienceCard}
</Container>
);
};
export default Layout;
๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ: ์๋ฌ, ๋ก๋ฉ ์ฒ๋ฆฌ
๋ง์ฝ ๊ฒฝํ์นด๋ API๋ ์ฑ๊ณตํ์ง๋ง ์๊ธฐ์๊ฐ์ API๋ฅผ ์คํจํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ ํ๋ฉด์ ๋ณด์ฌ์ค ์ ์๋ค.
์๋ ์ด๋ฌํ ํ๋ฉด์ ์ปดํฌ๋ํธ ๋ด๋ถ์์ if๋ฌธ์ ์ฌ์ฉํด์ ์ฒ๋ฆฌํ๊ณ ์์๋ค.
์ด์ ์ฝ๋
// components/ResumeForm.tsx
const ResumeForm = () => {
...
if (questionStatus === 'loading') return <Spinner />;
if (!question && questionStatus !== 'loading') return <NotFoundResume />;
return (
<form onSubmit={handleResumeSubmit}>
<FormHeader />
<textarea
ref={titleTextareaRef}
value={title ?? ''}
onChange={handleTitleChange}
onBlur={handleTitleBlur}
maxLength={MAX_LENGTH.TITLE}
placeholder="๋ฌธํญ ์ง๋ฌธ์ ์ ์ด๋ณด์ธ์."
className="w-full min-h-[96px] py-[6px] resize-none subhead2 placeholder:text-light"
/>
...
)
};
ํ๋์ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๋ก๋ฉ๊ณผ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๋ชจ๋ ํ๊ณ ์๋ค.
๋ง์ฝ ์๋ฌ ์ผ์ด์ค๊ฐ ๋ ์๊ธฐ๋ ๊ฒฝ์ฐ์๋ ์ด ์ปดํฌ๋ํธ๋ ์ ์ ๊ฑฐ๋ํด์ง ๊ฒ์ด๋ค.
์ดํ ์ฝ๋
// apps/resumes/[questionId]/page.tsx
const Page = () => {
return (
<form onSubmit={handleResumeSubmit}>
<FormHeader />
<textarea
ref={titleTextareaRef}
value={title ?? ''}
onChange={handleTitleChange}
onBlur={handleTitleBlur}
maxLength={MAX_LENGTH.TITLE}
placeholder="๋ฌธํญ ์ง๋ฌธ์ ์ ์ด๋ณด์ธ์."
className="w-full min-h-[96px] py-[6px] resize-none subhead2 placeholder:text-light"
/>
...
)
};
// apps/resumes/[questionId]/error.tsx
const Error = () => <NotFoundResume />;
ํ ํ์ผ์์ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ํจ๊ป ์์๋ ๊ฒ์ ํ์ผ๋ก ๋ถ๋ฆฌํ์ฌ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ ์ ์์๋ค.
๊ฒฐ๊ณผ
์ฑ๋ฅ
Parallel Routing์ ์ ์ฉํ ๊ฒฐ๊ณผ, 10์ด -> 603๋ฐ๋ฆฌ์ด๋ก 9.5์ด๋ฅผ ๋จ์ถ์์ผฐ๋ค.
ํผ์ผํ ์ด์ง๋ก ํ์ฐํ๋ฉด ์ฝ 94.13% ๋ก๋ฉ ์๋๊ฐ ์ค์ด๋ค์๋ค.
์ฝ๋
Parallel Routing์ ํตํด ์ฑ๋ฅ ๋ฟ๋ง ์๋๋ผ ํด๋ฆฐํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์๋ค.
- ๊ฐ ํ์ด์ง์ ๋ก๋ฉ ์ํ์ ์๋ฌ ์ํ๋ฅผ ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ ์ ์๋ค.
- ๋ด๋ถ ์ปดํฌ๋ํธ์ ๋ณต์กํ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ์ค์ผ ์ ์๋ค.
- ๋ ๋ฆฝ์ ์ผ๋ก ํ์ด์ง๋ฅผ ๋ถ๋ฆฌํ์ฌ ๋ ์ด์์์ด ๊ฑฐ๋ํด์ง๋ ๊ฒ์ ๋ง์ ์ ์๋ค.
'๐ ํ๋ก์ ํธ > ์ธ์ฌ์ดํธ์์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ธ์ฌ์ดํธ์์] React-Query ๋ฌดํ์คํฌ๋กค ์ ์ฉ๊ธฐ (1) | 2023.07.10 |
---|