์ฒ์์ ๊ตฌ์ํ UI ๋์์ธ์ ๋ฐ๊พธ๋ฉด์ ์ด ๋ฐฉ์์ด ๋ ์ ํฉํ๋ค ์๊ฐ๋์ด ๋ณ๊ฒฝํ๋ค.
์ด๊ฒ ์ฒ์ ๋์๋ ํผ๊ทธ๋ง์ด๊ณ , ์ด๋๋ ์ ์ญ์ผ๋ก ๋ชจ๋ฌ ๊ด๋ฆฌํด์ฃผ๋ ๋ฐฉ์์ผ๋ก redux-toolkit์ ์ฌ์ฉํ๋ ค๊ณ ํ๋ค.
โก๏ธ redux-toolkit์ ์ด์ฉํด์ ๋ชจ๋ฌ ์ํ๊ด๋ฆฌ
01. ์ ์ญ์์ ์ํ ๊ด๋ฆฌ๋๋ ๋ชจ๋ฌ ๋ง๋ค๊ธฐ (Next.js v14, redux-toolkit)
์ ๋ฒ์ ๋ง๋ ๋ชจ๋ฌ์ ๋ชจ๋ฌ์์ crudํ๋ ๊ธฐ๋ฅ๋ง์ ๊ฐ์ก์๋๋ฐ ์ด๋ฒ์๋ ์ฌ๋ผ์ด๋, ๋ชจ๋ฌ ๋ด์ ๋ชจ๋ฌ ํ์ ์ด ์ง์ ๋ ๋ฒํผ,๊ทธ๋ฆฌ๊ณ ๋ฒํผ์ ํด๋นํ๋ ๋ชจ๋ฌ form, ...... ๊ทธ์ผ๋ง๋ก ๋ชจ๋ฌ ์ผ๋๊ธฐ๋ผ๊ณ ๋ณผ ์ ์
nuew.tistory.com
๊ทธ๋ฌ๋ค๊ฐ ๋ค์์ด ๋ฐ๋ ๋์์ธ์ด๊ณ , ์ด๋ ๊ฒ ํ๋ ค๋ฉด ์ด๋ค ๋ฐฉ์์ด ์ข์๊น ๊ณ ๋ฏผํ๋ค๊ฐ Next.js์ ๊ธฐ๋ฅ ์ค ํ๋์ธ parallel routes์ intercepting routes๋ฅผ ์ฌ์ฉํด์ ๊ตฌํํ๊ธฐ๋ก ํ๋ค.
๋ณ๋ ฌ ๋ผ์ฐํ ์ ๊ตฌํํด์ ์ค๊ฐ์ ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ก์ฑ๋ ๊ฒ์ธ๋ฐ, ๊ฐ๋จํ ์ค๋ช ํ๋ฉด ์ค๊ฐ์ ๋ง๋ ํ์ ํ์ด์ง๋ก์ ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ก์ฑ๋ ๊ฒ์ด๋ค.
๋ค์์ ๋ณ๋ ฌ ๋ผ์ฐํ ์ ๊ฐ๋ก์ฑ๊ธฐ๋ฅผ ํตํ ๋ชจ๋ฌ ๋ง๋ค๊ธฐ์ ์ฅ์ ์ด๋ค.
- URL์ ํตํด ๋ชจ๋ฌ ๋ด์ฉ์ ๊ณต์ ํ ์ ์๋ค
- ๋ค๋ก ๊ฐ๊ธฐ์ ์์ผ๋ก ๊ฐ๊ธฐ๋ก ๋ท ํ์ด์ง์ ๋ ๋๋ง ์์ด ๋ชจ๋ฌ๋ง ์ด๊ณ ๋ซ์ ์ ์๋ค
์ ์ฉ ์ ํํ ๋ฆฌ์ผ
๋ฌธ์๋ง ๋ณด๊ธฐ์๋ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ด ๋ง์๋ค. ์ง๊ธ ์๊ฐํ๋ฉด ๋ผ์ฐํธ ์ค์ ๋ง ์ ํด์ฃผ๋ฉด ๋๋ ๊ฑด๋ฐ ์ฒ์์๋ ์์ ๋ ํฌ๋ฅผ ๋ด๋ ์ด๋ฆฌ๋ฅ์ ํ๋ค
ex.
/app/photo ํ์ด์ง์์ /app/photo/text url๋ก ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ก์ฑ๊ธฐ, ๋ณ๋ ฌ ๋ผ์ฐํ ์ ์ด์ฉํด ๋ชจ๋ฌ์ ๋์ด๋ค๊ณ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ฉด ๋๋ค.
๋จผ์ /photo ํ์์ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ๋ค.
// /app/photo/page.js
import Link from "next/link";
export default function Photo() {
return (
<>
<h1>Photo List</h1>
<Link href="/photo/text" className="text-white">
Photo text
</Link>
</>
);
}
// /app/photo/layout.js
export default function PhotoLayout({ children, modal }) {
return (
<div>
{modal}
{children}
</div>
);
}
๊ทธ๋ฆฌ๊ณ /photo/[id]
// /app/photo/[id]/page.js
export default function PhotoId({ params }) {
console.log({...params})
return <h1 className="text-white">This is photo/id==? {params.id}</h1>;
}
/app ํ์๊ฐ ์๋, /photo ํ์์ @modal๋ก ์์ํ๋ ํด๋๋ฅผ ๋ง๋ค๊ณ , ๋ณ๋ ฌ ๋ผ์ฐํ ์ค์ ์ ํ๋ค.
@์ด๋ฆ์ modal๋ก ์ค์ ํ ์ด์ ๋ /photo/layout.js ์์ children๊ณผ ํจ๊ป modal ๋ก ์ค์ ์ ํด์คฌ๊ธฐ ๋๋ฌธ์ ๋์ ๋์ผํ๊ฒ ๋ง์ถฐ์ค๋ค.
/photo/@modal
// /src/app/photo/@modal/default.js
export default function ModalDefault() {
return null;
}
// src/app/photo/@modal/page.js
export default function ModalPage() {
return <div>Modal Page</div>;
}
์ด์ ๊ฒฝ๋ก ๊ฐ๋ก์ฑ๊ธฐ๋ฅผ ํ ๊ฑด๋ฐ, ๋ /photo/text ์ฒ๋ผ @modal ํด๋ ๋ฐ์ ๋ง๋ค์ด์ผ ํ๋๋ฐ ํด๋ ๊ตฌ์กฐ์ ๋๋จ๊ณ ์์ ๋ผ์ฐํธ๋ฅผ ๊ฐ๋ก์ฑ์ผํ๊ธฐ ๋๋ฌธ์ @modal/(..)photo/[id]์ ๊ฐ์ ํด๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค.
๊ฒฝ๋ก๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋๋ฌธ์ ๋๋จ๊ณ ์์ธ ๊ฒ: src/app/photo/@modal/(..)photo/text/page.js
// src/app/photo/@modal/(..)photo/text/page.js
export default function InterceptedModalPhotoId({ params }) {
return <h1 className="text-white">Intercepted Photo Id {params.id}</h1>;
}
ํ๊ณ params์ ๊ฐ์ console๋ก ์ฐ์ด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด text๋ก ์ ๋์จ๋ค.
์ด์ ์คํ์์ผ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ ๋๋ค.
๋ค๋ก ๊ฐ๊ธฐ, ์์ผ๋ก ๊ฐ๊ธฐ๋ฅผ ํด๋ ๋ท ๋ฐฐ๊ฒฝ์ ๋ณ์ด ๊ทธ๋๋ก ์๋ ๊ฒ์ ์ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ก๊ณ ์นจ์ ํ์ ๋๋ intercepted ๋์ง ์์ ๊ธฐ๋ณธ ์ค์ ๋ ํ์ด์ง๊ฐ ๋์ค๋ ๊ฒ์ ์ ์ ์๋ค.
์ด๋ ๊ฒ,, ํฐ ์ฝ์ง์ ๋๋ด๊ณ ๋ด ์ํฉ์ ๋ง์ถฐ ์ ์ฉํ๋ค.
์ค์ ์ ์ฉ ๊ณผ์
/timeline ํ์ด์ง์์ ์๊ฐ์ ๋ชจ๋ฌ ํ์ด์ง๊ฐ ํ์ํ๊ณ ์ต์ข ํด๋ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.
๋์๊ฒ /timeline/event ๋ /timeline/movie ๊ฐ ํ์ํ์
๋จผ์ /timeline ํด๋๋ด์ @modal ํด๋๋ฅผ ๋ฃ๊ณ ์ค์ ํ default.js์ผ๋ก ํ์ฌ๊ธ ์ด๊ธฐ ๋ก๋ ๋๋ ์๋ก๊ณ ์นจ ์ค์ ์ผ์นํ์ง ์๋ ์ฌ๋กฏ์ ๋ํด ๋ ๋๋งํ ์ ์๋ค.
// app/timeline/@modal/default.js
export default function Default() {
return null;
}
// app/timeline/@modal/page.js
"use client";
export default function TimelinePage() {
return <h1>/timeline Modal Page</h1>;
}
/timeline/@modal/(..)timeline/event/page.js์ /timeline/@modal/(..)timeline/event/page.js์ ๋์ธ ๋ด์ฉ์ ์์์ ๋ง๋ค์ด์ค๋ค.
๊ทธ๋ฆฌ๊ณ /timeline/[id]/page.js์ฒ๋ผ ์ค์ ํ์ด์ง๊ฐ ์์ด์ผ (..)๋ก ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ก์ฑ ์ ์๊ธฐ ๋๋ฌธ์ ๋ง๋ค์ด์ค๋ค.
// app/timeline/[id]/page.js
export default function TimelineId({ params }) {
console.log({ ...params });
return <h1 className="text-white">This is /timeline/id: {params.id}</h1>;
}
/timeline/layout.js
// /app/timeline/layout.js
export default function TimelineLayout({ children, modal }) {
return (
<>
<div>{children}</div>
<div>{modal}</div>
</>
);
}
/timeline ์์ ํ ์คํธ ํด๋ณด๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ๋งํฌ๋ฅผ ๊ฑธ์ด์คฌ๋ค.
// /app/timeline/page.js
"use client";
import Link from "next/link";
export default function Timeline() {
return (
<div className="text-white">
<Link href="/timeline/event">์ฌ๊ฑด ๋ฑ๋กํ๊ธฐ</Link>
<Link href="/timeline/movie">์ํ ๋ฑ๋กํ๊ธฐ</Link>
</div>
);
}
์ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
์ฌ๊ฑด ๋ฑ๋กํ๊ธฐ => ๊ฐ๋ก์ฑ์ง ๊ฒฝ๋ก๊ฐ ๋์๊ณ ,
์ํ ๋ฑ๋กํ๊ธฐ => ๊ฐ๋ก์ฑ์ง ๊ฒฝ๋ก๊ฐ ๋์จ ํ ๋ด๊ฐ ์๋ก๊ณ ์นจ์ ํ๋ ๋ชจ๋ฌ ํ์ด์ง๊ฐ ์๋ ๋ํดํธ๊ฐ์ผ๋ก ์ค์ ํด์ค ํ์ด์ง๊ฐ ๋์ค๊ฒ ๋๋ค.
์์ ์์ gif์ฒ๋ผ ๋ท ๋ฐฐ๊ฒฝ์ ๋ณ์ด ๊ณ ์ ๋์ด ์๋ ๊ฒ์ ๋ณด๋ฉด ๊ธฐ์กด ํ๋ฉด(/timeline)์ ๋ฆฌ๋ ๋๋งํ์ง์๊ณ ๊ณ ์ ์ํจ ๊ทธ๋๋ก ๊ทธ ์์ ๋ชจ๋ฌ์ ๋์ด๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
'What I Learn' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Toast ์ ์ฉ๊ธฐ (0) | 2024.12.10 |
---|---|
scroll ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ๋ฌดํ ์คํฌ๋กค ๊ตฌํ (1) | 2024.10.27 |
OSSCA: LLM ์กฐ์ฌ, Continue ๋ถ์ ๋ฐ ์ ๋ฆฌ (8) | 2024.10.24 |
next-auth๋ฅผ ์ฌ์ฉํ ์นด์นด์ค ๋ก๊ทธ์ธ (4) | 2024.10.22 |
exclude a page from next.js root layout (0) | 2024.10.16 |