createBrowserRouter๋ฅผ ํ†ตํ•œ Router๊ธฐ๋Šฅ ์ถ”๊ฐ€

SPA๋Š” "Single Page Application"์˜ ์•ฝ์ž๋กœ, ์›น ์„œ๋น„์Šค์˜ ์ค‘์š”ํ•œ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Profile Picture
adultlee
2023-11-13

์›๋ณธ

SPA์—์„œ์˜ Client side routing ์ด๋ž€?

SPA๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”? (์ด๋ฏธ์ง€ ์ถœ์ฒ˜)

SPA๋Š” "Single Page Application"์˜ ์•ฝ์ž๋กœ, ์›น ์„œ๋น„์Šค์˜ ์ค‘์š”ํ•œ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. SPA๋Š” ๋‹จ์ผ HTML ํŒŒ์ผ์„ ๋กœ๋“œํ•œ ํ›„, ์‚ฌ์šฉ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ๋‹ค์–‘ํ•œ ํ™”๋ฉด ๋˜๋Š” ๋ทฐ๋กœ ์ด๋™ํ•  ๋•Œ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜์ง€ ์•Š๊ณ ๋„ ์ปจํ…์ธ ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ SPA์˜ ํŠน์ง•์€ ์›น ์„œ๋น„์Šค๋ฅผ ๋” ๋น ๋ฅด๊ณ  ๋ฐ˜์‘์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉฐ UX๋ฅผ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

Client Side Routing์€ SPA์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋œ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. SPA์—์„œ๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ดˆ๊ธฐ์— ํ•œ ๋ฒˆ๋งŒ HTML, CSS, ๋ฐ JavaScript ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๊ณ  ์ดํ›„์—๋Š” ์„œ๋ฒ„์— ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜์ง€ ์•Š๊ณ  ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํŽ˜์ด์ง€ ๊ฐ„์˜ ์ „ํ™˜์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ Client Side Routing์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” spa์˜ ํŠน์ง•์ค‘ ํ•˜๋‚˜์ธ Client Side Routing์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์š”์ฒญ ์—†๋Š” ํŽ˜์ด์ง€ ์ „ํ™˜

Client Side Routing์€ ์‚ฌ์šฉ์ž๊ฐ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ๋•Œ ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜์ง€ ์•Š๊ณ ๋„ ํŽ˜์ด์ง€๋ฅผ ๋น ๋ฅด๊ฒŒ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์„œ๋ฒ„์™€์˜ ํ†ต์‹  ๋ถ€๋‹ด์„ ์ค„์ด๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅธ ์‘๋‹ต ์‹œ๊ฐ„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ๋กœ๊ณ ์นจ ์—†๋Š” ํŽ˜์ด์ง€ ์ด๋™

์ „ํ†ต์ ์ธ ์›น ์‚ฌ์ดํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ๋งํฌ๋ฅผ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋กœ๋“œ๋˜๋ฉฐ ์ „์ฒด ํ™”๋ฉด์ด ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜๋ฉด ํŽ˜์ด์ง€ ์ด๋™ ์‹œ์— ์ƒˆ๋กœ๊ณ ์นจ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ํŽ˜์ด์ง€์˜ ์ผ๋ถ€๋งŒ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค. ์ด๋กœ์จ ๋ถ€๋“œ๋Ÿฌ์šด UX์„ ์ œ๊ณตํ•˜๋ฉฐ ํ™”๋ฉด ๊นœ๋นก์ž„์ด๋‚˜ ์‘๋‹ต ์ง€์—ฐ์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.

๋™์  UI ์—…๋ฐ์ดํŠธ

Client Side Routing์„ ํ†ตํ•ด ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ์— UI๋ฅผ ๋™์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ํŽ˜์ด์ง€ ๋‚ด์šฉ์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ์จ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด๋‹ค ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•˜๊ณ  ๋™์ ์ธ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

URL ๊ด€๋ฆฌ

ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์€ URL์„ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ํŽ˜์ด์ง€ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ธŒ๋ผ์šฐ์ €์˜ ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฐ ์•ž์œผ๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์„ ์ง€์›ํ•˜๊ณ , ๋ถ๋งˆํฌ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ƒํƒœ๋กœ ๊ณต์œ ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

SPA์™€ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์€ ๋ชจ๋‘ ํ˜„๋Œ€์ ์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์—์„œ ์ค‘์š”ํ•œ ์š”์†Œ๋กœ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅด๊ณ  ๋ถ€๋“œ๋Ÿฌ์šด UX๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐ ํฌ๊ฒŒ ๊ธฐ์—ฌํ•ฉ๋‹ˆ๋‹ค. React Router๋Š” SPA์˜ Client Side Routing์„ ๊ตฌํ˜„ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

createBrowserRouter๋ž€?

createBrowserRouter๋Š” React Router v6์—์„œ ์ƒˆ๋กญ๊ฒŒ ๋„์ž…๋œ API ์ค‘ ํ•˜๋‚˜๋กœ, ๋ผ์šฐํ„ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋ผ์šฐํ„ฐ ๊ตฌ์„ฑ์„ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์„ ์–ธ์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋ฉฐ, ์ด๋ฅผ BrowserRouter ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•˜์—ฌ ๋ผ์šฐํŒ…์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. createBrowserRouter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด route์— ๋Œ€ํ•œ ์ƒ์„ธํ•œ ์ •์˜์™€ route์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ถ”๊ฐ€ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์‚ฌ์šฉํ•ด์˜ค๋˜ Router ์ปดํฌ๋„ŒํŠธ์™€ ๋น„๊ตํ•ด์„œ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// React Router v6์—์„œ์˜ Route ์‚ฌ์šฉ ์˜ˆ
import { Route, Routes } from "react-router-dom";

function App() {
	return (
		<Routes>
			<Route path="/" element={<HomePage />} />
			<Route path="about" element={<AboutPage />} />
			{/* ์ถ”๊ฐ€ Route ์ •์˜ */}
		</Routes>
	);
}

// React Router v6์—์„œ์˜ createBrowserRouter ์‚ฌ์šฉ ์˜ˆ
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
	{
		path: "/",
		element: <HomePage />,
		// ์—ฌ๊ธฐ์— ํ•˜์œ„ ๋ผ์šฐํŠธ๋‚˜ ๋กœ๋”(loader), ์•ก์…˜(action) ๋“ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
	},
	{
		path: "about",
		element: <AboutPage />,
	},
	// ์ถ”๊ฐ€ ๋ผ์šฐํŠธ ์ •์˜
]);

function App() {
	return <RouterProvider router={router} />;
}

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์˜ ์ฐจ์ด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Route ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, createBrowserRouter๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด ์ƒ์„ธํ•œ ์ฝ”๋“œ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

{
    path: "/",
    element: <Root />,
    loader: rootLoader,
    children: [
      {
        path: "team",
        element: <Team />,
        loader: teamLoader,
      },
    ],
  },

์ด๋•Œ ํ•ด๋‹น ์ฝ”๋“œ์— ๋Œ€ํ•œ children์„ ์‚ฌ์šฉํ•˜๋ฉฐ, RootํŽ˜์ด์ง€ ๋‚ด๋ถ€ ํ•˜์œ„ path๊ฐ€ team์˜ ๊ฒฝ์šฐ Team ์ด๋ผ๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด rendering์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค ์œ„์˜ ์ฝ”๋“œ์—์„œ ์ฃผ์˜ ํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์€ loader์ž…๋‹ˆ๋‹ค.

loader

๊ฐ ๊ฒฝ๋กœ๋Š” ๋ Œ๋”๋ง๋˜๊ธฐ ์ „์— ๊ฒฝ๋กœ ์š”์†Œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” "๋กœ๋”" ๊ธฐ๋Šฅ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

createBrowserRouter([
	{
		path: "/teams/:teamId",
		loader: ({ params }) => {
			return fakeGetTeam(params.teamId);
		},
	},
]);
// ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ ํŽ˜์ด์ง€๋ฅผ loadํ•˜๊ธฐ ์ „๋ถ€ํ„ฐ loader๋ฅผ ํ†ตํ•ด์„œ ์—๋Ÿฌ, ํ˜น์€ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌํŒ€(NDD)์˜ ์„œ๋น„์Šค์ธ ๊ณฐํ„ฐ๋ทฐ๋Š” ์„œ๋น„์Šค ํŠน์„ฑ์ƒ ๋ฉด์ ‘์— ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— ์—ฌ๋Ÿฌ setting์„ ํ•ด์•ผํ•˜๋Š” ๊ณผ์ •์„ ๊ฒธํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.(๋ฌธ์ œ๋ฅผ ์„ ์ •, ์นด๋ฉ”๋ผ ๋ฐ ๋งˆ์ดํฌ ์—ฐ๊ฒฐ, ์ €์žฅ์†Œ ์„ ํƒ ๋“ฑ) ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€๋ณ„ route๋ฅผ ์ด๋™ํ• ๋•Œ ์—ฌ๋Ÿฌ error์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผํ•˜๋Š”๋ฐ, ์ด๋•Œ ํ•ด๋‹น ํŒŒ์ผ์—์„œ ๋ช…ํ™•ํ•œ ์ฑ…์ž„ ๋ถ„๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ• ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋œ ์ดํ›„๊ฐ€ ์•„๋‹Œ, ์• ์ดˆ์— router์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด์„œ ๋ง‰์•„์ค€๋‹ค๋ฉด ์ข€ ๋” ๋ช…ํ™•ํ•œ ์ฑ…์ž„์„ ๊ฐ€์ง„๋‹ค๋Š” ์ƒ๊ฐ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฟ์ด ์•„๋‹ˆ๋ผ lazy-loading์„ ํ†ตํ•œ ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ…์—๋„ ๊ทนํžˆ ์œ ๋ฆฌ ํ•ฉ๋‹ˆ๋‹ค.

lazy

react-router-dom/lazy

lazy-loader๋ฅผ ํ†ตํ•ด์„œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ธ๋“ค์„ ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๋ฉด์„œ ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ์ฝ”๋“œ ๋ถ„ํ™œ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ํš๊ธฐ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค๋Š” ์ ์ด ๋งค๋ ฅ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ข…ํ•ฉ์ ์ธ ๊ธฐ๋Šฅ๊ณผ ์˜ˆ์‹œ (by gpt)

์•„๋ž˜๋Š” createBrowserRouter์˜ ์ข…ํ•ฉ์ ์ธ ๊ธฐ๋Šฅ๊ณผ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

  1. ์„ ์–ธ์  ๋ผ์šฐํŠธ ๊ตฌ์„ฑ: createBrowserRouter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด JavaScript ๊ฐ์ฒด๋กœ ๋ผ์šฐํŠธ๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŠธ์˜ ๊ตฌ์กฐ์™€ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  2. ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋ฐ ์ฝ”๋“œ ๋ถ„ํ•  ์ง€์›: ๋ผ์šฐํŠธ ๊ฐ์ฒด ๋‚ด์—์„œ loader ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์„œ, ํ•ด๋‹น ๋ผ์šฐํŠธ๊ฐ€ ํ™œ์„ฑํ™”๋  ๋•Œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, import()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋กœ๋“œํ•˜๋Š” ์ฝ”๋“œ ๋ถ„ํ• ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋‚ด์žฅ๋œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง: createBrowserRouter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ์šฐํŠธ ๊ฐ์ฒด์— errorElement๋ฅผ ์ œ๊ณตํ•˜์—ฌ ํŠน์ • ๊ฒฝ๋กœ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  4. ํ–ฅ์ƒ๋œ ์„ฑ๋Šฅ: ์ƒˆ๋กœ์šด ๋ผ์šฐํ„ฐ๋Š” ๋ผ์šฐํŠธ ๋งค์นญ๊ณผ ๋ Œ๋”๋ง ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ํ–ฅ์ƒ๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  5. ํžˆ์Šคํ† ๋ฆฌ API์™€์˜ ํ†ตํ•ฉ: createBrowserRouter๋Š” HTML5 ํžˆ์Šคํ† ๋ฆฌ API์™€ ๊ธด๋ฐ€ํ•˜๊ฒŒ ํ†ตํ•ฉ๋˜์–ด ์žˆ์–ด, ๋ธŒ๋ผ์šฐ์ €์˜ ๋’ค๋กœ ๊ฐ€๊ธฐ/์•ž์œผ๋กœ ๊ฐ€๊ธฐ ๊ธฐ๋Šฅ๊ณผ ์™„๋ฒฝํ•˜๊ฒŒ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค.

  6. ๊ฒฝ๋กœ ๋ณดํ˜ธ ๊ธฐ๋Šฅ: createBrowserRouter๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, loader ํ•จ์ˆ˜ ๋‚ด์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋Š” ๋“ฑ์˜ ๋ณด์•ˆ ๊ฒฝ๋กœ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  7. ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ: ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ๋ฅผ ํ†ตํ•ด ๋ ˆ์ด์•„์›ƒ ๋‚ด์— ํ•˜์œ„ ๊ฒฝ๋กœ๋“ค์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ UI ๊ตฌ์กฐ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { createBrowserRouter, RouterProvider } from "react-router-dom";
import React, { lazy, Suspense } from "react";
import Layout from "./components/Layout";
import ErrorPage from "./components/ErrorPage";
import Loading from "./components/Loading";
import { fetchUserData } from "./utils/auth";

// ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ lazy๋กœ ๋ถˆ๋Ÿฌ์˜ด์œผ๋กœ์จ ์ฝ”๋“œ ๋ถ„ํ•  ๊ตฌํ˜„
const HomePage = lazy(() => import("./pages/HomePage"));
const ProfilePage = lazy(() => import("./pages/ProfilePage"));
const LoginPage = lazy(() => import("./pages/LoginPage"));

const router = createBrowserRouter([
	{
		path: "/",
		element: <Layout />, // ๊ธฐ๋ณธ ๋ ˆ์ด์•„์›ƒ
		errorElement: <ErrorPage />, // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ํ‘œ์‹œ๋  ์ปดํฌ๋„ŒํŠธ
		children: [
			{
				index: true,
				element: (
					<Suspense fallback={<Loading />}>
						<HomePage />
					</Suspense>
				),
			},
			{
				path: "profile",
				element: (
					<Suspense fallback={<Loading />}>
						<ProfilePage />
					</Suspense>
				),
				loader: async () => {
					// ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ
					const userData = await fetchUserData();
					if (!userData) {
						throw new Error("User not found");
					}
					return userData;
				},
			},
			{
				path: "login",
				element: (
					<Suspense fallback={<Loading />}>
						<LoginPage />
					</Suspense>
				),
			},
		],
	},
	// ๊ฒฝ๋กœ ๋ณดํ˜ธ๋ฅผ ์œ„ํ•œ ์˜ˆ์‹œ
	{
		path: "protected",
		element: (
			<Suspense fallback={<Loading />}>
				<ProtectedPage />
			</Suspense>
		),
		loader: async () => {
			const user = await fetchUserData();
			if (!user) {
				// ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
				throw new Response(null, { status: 403 });
			}
		},
	},
]);

function App() {
	return <RouterProvider router={router} />;
}

export default App;

createBrowserRouter ๊ฒฐ๊ณผ

์ด์Šˆ๋ฐœ์ƒ ๐Ÿ”ฅ

์ด์Šˆ : react-router-dom์˜ Link ํƒœ๊ทธ๋กœ๋Š” ์ž˜ ์ด๋™ํ•˜์ง€๋งŒ ์ด๋™ํ•œ ์œ„์น˜์—์„œ ์ƒˆ๋กœ ๊ณ ์นจ์„ํ•˜๋ฉด ์ด๋™์ด ๋ถˆ๊ฐ€ํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

์ด์œ 

์ด ๋ฌธ์ œ๋Š” Single Page Applications (SPA)์˜ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…๊ณผ ์„œ๋ฒ„ ์ธก ๋ผ์šฐํŒ… ๋ฐฉ์‹์˜ ์ฐจ์ด์—์„œ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. react-router-dom ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ ํ‘œ์‹œ์ค„์˜ URL์„ ๋ณ€๊ฒฝํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋™์ ์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

์ด์™€ ๋Œ€์กฐ์ ์œผ๋กœ, ์„œ๋ฒ„ ์ธก ๋ผ์šฐํŒ…์€ URL์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„๋กœ ์ƒˆ ์š”์ฒญ์„ ๋ณด๋‚ด ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ฉ๋‹ˆ๋‹ค. SPA์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ์„œ๋ฒ„๋Š” ์–ด๋–ค ํŠน์ • ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชฐ๋ผ์„œ 404 Not Found ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, http://example.com/user ํŽ˜์ด์ง€๋ฅผ ๋ณด๊ณ  ์žˆ๋‹ค๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด, ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„์— /user ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ƒˆ ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. SPA๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ์ด ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ์„ค์ •๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์„œ๋ฒ„๋Š” 404 ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š”, ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํ„ฐ๋งŒ์ด /user ๊ฒฝ๋กœ๊ฐ€ ์œ ํšจํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๊ณ , ์„œ๋ฒ„๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด historyApiFallback ์„ค์ •์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ์„ค์ •์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด, Webpack Dev Server๋Š” ๊ฐœ๋ฐœ ์ค‘์— ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŠธ์— ๋Œ€ํ•œ 404 ์‘๋‹ต์„ **index.html**๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” **index.html**์ด ์‹ค์ œ๋กœ๋Š” SPA์˜ ์ง„์ž…์ ์ด๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์ธก JavaScript๊ฐ€ ํ•„์š”ํ•œ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ URL์„ ์ž…๋ ฅํ•˜์—ฌ ํŠน์ • ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ•  ๋•Œ, historyApiFallback ์„ค์ •์ด ์žˆ๋Š” ์„œ๋ฒ„๋Š” ์š”์ฒญ์„ **index.html**๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๊ณ , ๊ทธ ํ›„์— **react-router-dom**์ด URL์„ ํ™•์ธํ•˜์—ฌ ์ ์ ˆํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ •์˜ํ•œ ๋ผ์šฐํŠธ๊ฐ€ ์„œ๋ฒ„ ์ธก์—์„œ๋„ ๋ฌธ์ œ์—†์ด ์ž‘๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

image

๋‹ค์Œ ์ฝ”๋“œ์™€ ๊ฐ™์ด webpack ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์คŒ์œผ๋กœ์„œ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋งบ์Œ๋ง

์ง€๊ธˆ๊นŒ์ง€ ํ”„๋กœ์ ํŠธ์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ธ createBrowserRouter๋ฅผ ํ†ตํ•œ Router์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๋ผˆ๋Œ€๋ฅผ ์žก์•˜์Šต๋‹ˆ๋‹ค. ์•„์ง์€ ๋ฐ˜์˜๋˜์ง€ ์•Š์•˜์œผ๋‚˜, setting ํŽ˜์ด์ง€๋ฅผ ์˜ค๊ฐ€๋ฉฐ ๋ฐœ์ƒํ•  ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ์˜ ๋ฌธ์ œ๋ฅผ createBrowserRouter์—์„œ ํ•ด๊ฒฐํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

ํ•ด๋‹น ๊ฐœ๋ฐœ ๋‚ด์šฉ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ PR์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

+) ๋ฉ˜ํ† ๋‹˜์˜ comment

์–ธํ—คํ”ผ ์ผ€์ด์Šค์— ๋Œ€ํ•œ ๊ฐ„๋‹จ ์ •๋ฆฌ

ยฉ 2024 Adultlee. All rights reserved.Made with โค by ์ด์„ฑ์ธ