Routes

๋ผ์šฐํ„ฐ๋ž€?

๋ผ์šฐํŒ…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋„๊ตฌ

URL๊ณผ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๋งคํ•‘์„ ๊ด€๋ฆฌํ•˜๊ณ , URL ๋ณ€๊ฒฝ์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ์‹œํ‚ค๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

React Router

React์—์„œ ๋ผ์šฐํŒ…์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Install

npm i react-router-dom

Browser Router

๋ธŒ๋ผ์šฐ์ €์— ๋‚ด์žฅ๋œ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ํƒ์ƒ‰ ๋ฐ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ History API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CSR ๋ผ์šฐํŒ…์„ ๊ตฌํ˜„

  • URL๊ณผ ๋งคํ•‘๋˜๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง

  • history ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋’ค๋กœ๊ฐ€๊ธฐ, ์•ž์œผ๋กœ๊ฐ€๊ธฐ, ์ƒˆ๋กœ๊ณ ์นจ๋“ฑ์˜ ๋™์ž‘์„ ์ฒ˜๋ฆฌ

declare function BrowserRouter(
  props: BrowserRouterProps
): React.ReactElement;

interface BrowserRouterProps {
  basename?: string;
  children?: React.ReactNode;
  window?: Window;
}

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” window ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, BrowserRouter๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€ ์™ธ๋ถ€(main.js ๋“ฑ)์—์„œ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

// main.js
root.render(
    <StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </StrictMode>,
  );
};

Memory Router

Test ํ™˜๊ฒฝ์—์„œ BrowserRouter ๋Œ€์‹  MemoryRouter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์šฐํŒ… ํ™˜๊ฒฝ ๊ตฌ์ถ•ํ•œ๋‹ค.

๋ง ๊ทธ๋Œ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์—์„œ ๋ผ์šฐํŒ…

declare function MemoryRouter(
  props: MemoryRouterProps
): React.ReactElement;

interface MemoryRouterProps {
  basename?: string;
  children?: React.ReactNode;
  initialEntries?: InitialEntry[];
  initialIndex?: number;
}
  • initialEntries โ†’ ์ดˆ๊ธฐ ์—”ํŠธ๋ฆฌ ๋ชฉ๋ก ์„ค์ •, ์ฆ‰ ํ…Œ์ŠคํŠธํ•  ํŽ˜์ด์ง€์˜ ์ฒซ ๋ Œ๋”๋ง ๊ฒฝ๋กœ ์„ค์ •

    • ๋ฐฐ์—ด์ธ ์ด์œ ๋Š” ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ๊ณผ ๋™์ผ, (๋’ค๋ก๊ฐ€๊ธฐ, ์•ž์œผ๋กœ๊ฐ€๊ธฐ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•จ)

  • initialIndex โ†’ ์ดˆ๊ธฐ ์—”ํŠธ๋ฆฌ ๋ชฉ๋ก[๋ฐฐ์—ด] ์ค‘ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ๊ฒฝ๋กœ๋ฅผ ์„ ํƒ

import { MemoryRouter } from 'react-router-dom';

describe('App', () => {
  it('render correctly', () => {
    render(
      <MemoryRouter>
        <Routes>
          <Route path="/" element={<App />} />
          <Route path="/dashboard" element={<DashBoard />} />
        </Routes>
      </MemoryRouter>,
    );

    expect(screen.getByText(/์ด๋‹ค์ž‰/)).toBeInTheDocument();
  });
});

ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•ด์„œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’ํ˜€๋ณด์ž

export function withRouter(routes, initialEntries = '/') {
  return (
    <MemoryRouter initialEntries={[initialEntries]}>
      <Routes>
        {routes}
      </Routes>
    </MemoryRouter>
  )
}

describe('App', () => {
  it('render correctly', () => {
    render(withRouter(
    <>
      <Route path="/" element={<App />} />
      <Route path="/dashboard" element={<DashBoard />} />
    </>
    ));

    expect(screen.getByText(/์ด๋‹ค์ž‰/)).toBeInTheDocument();
  });
});

Routes

์—ฌ๋Ÿฌ ๊ฒฝ๋กœ์˜ ๋ผ์šฐํŒ… ๊ทœ์น™์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ

์ž์‹์œผ๋กœ ์—ฌ๋Ÿฌ <Route /> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ–๋Š”๋‹ค.

interface RoutesProps {
  children?: React.ReactNode;
  location?: Partial<Location> | string;
}

<Routes location>
  <Route />
</Routes>;
  • children โ†’ ์ž์‹์œผ๋กœ <Route/> ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

  • location โ†’ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ๊ณต, ์ƒ๋žต์‹œ ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ € URL ๊ธฐ์ค€์œผ๋กœ ์ฒ˜๋ฆฌ

<Routes>
  <Route path="/" element={<HomePage />} />
  <Route path="/dashboard" element={<DashboardPage />} />
  <Route path="*" element={<NotFound />} />
</Routes>
  • location์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ํ•˜์œ„ ์ž์‹๋“ค์˜ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•˜์—ฌ ๊ฐ€์žฅ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„ ํ•ด๋‹น ๋ถ„๊ธฐ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค

  • ๋งค์นญ๋˜๋Š” ๋ผ์šฐํŒ… ๊ทœ์น™์ด ์—†์„ ๋•Œ ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๋‹ค. (catch-all ๋ผ์šฐํŒ…)

  • ์ค‘์ฒฉํ•˜์—ฌ ๋ผ์šฐํŒ… ๊ทœ์น™์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Route

๊ฒฝ๋กœ์™€ ๋งค์นญ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ง€์ •

interface RouteObject {
  path?: string;
  index?: boolean;
  children?: React.ReactNode;
  caseSensitive?: boolean;
  id?: string;
  loader?: LoaderFunction;
  action?: ActionFunction;
  element?: React.ReactNode | null;
  Component?: React.ComponentType | null;
  errorElement?: React.ReactNode | null;
  ErrorBoundary?: React.ComponentType | null;
  handle?: RouteObject["handle"];
  shouldRevalidate?: ShouldRevalidateFunction;
  lazy?: LazyRouteFunction<RouteObject>;
}
  • path โ†’ ์ปดํฌ๋„ŒํŠธ์™€ ์—ฐ๊ฒฐํ•  ๊ฒฝ๋กœ ์ง€์ •, :๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ Dynamic Segments๋ผ ํ•œ๋‹ค.

  • index โ†’ ์ธ๋ฑ์Šค ๊ฒฝ๋กœ ์—ฌ๋ถ€ ์ง€์ •

  • caseSensitive โ†’ ๊ฒฝ๋กœ์˜ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ์ผ์น˜์‹œํ‚ฌ์ง€ ์—ฌ๋ถ€ (default false)

  • element / Component โ†’ ๊ฒฝ๋กœ์™€ ์—ฐ๊ฒฐํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์ •ํ•œ๋‹ค.

Dynamic Segmenets๋ž€?

๋™์  ๊ฒฝ๋กœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜(params)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ผ์šฐํŠธ ๊ฒฝ๋กœ์˜ ์ผ๋ถ€, : ๊ธฐํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.

<Route
  path="/teams/:teamId"
  element={<Team />}
/>;

// Team
export default function TeamPage() {
const params = useParams();
  // path: /teams/hotspur ์ธ๊ฒฝ์šฐ params.teamId => hospur
  // path: /teams/real ์ธ๊ฒฝ์šฐ params.teamId => real
  return <p>{`params: ${params.teamId}`}</p>
}

Index Route๋ž€?

index ๊ฒฝ๋กœ์ด๊ธฐ ๋•Œ๋ฌธ์— path๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋ถ€๋ชจ ๊ฒฝ๋กœ๊ฐ€ ์ผ์น˜ํ•˜์ง€๋งŒ ์ž์‹ ๊ฒฝ๋กœ์ค‘ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์ด ์—†์„ ๋•Œ์— ๋ Œ๋”๋ง๋˜๋Š” ๊ธฐ๋ณธ ์ž์‹ ๊ฒฝ๋กœ์ด๋‹ค.

Outlet

๋ผ์šฐํ„ฐ์— ๋งค์นญ๋œ ํ•˜์œ„์˜ ๋‹ค๋ฅธ ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์œ„์น˜ํ•  ์˜์—ญ์„ ์ง€์ • (Slot ๊ฐœ๋…)

์ผ๋ฐ˜์ ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ์— ํ™œ์šฉ๋œ๋‹ค.

export default function Layout() {

  return (
    <>
      <header>Header</header>
      <main>
        <Outlet />
      </main>
      <footer>Footer</footer>
    </>
  );
};

Layout Route

๋ผ์šฐํŠธ ๋งค์นญ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š๋Š” ๊ป๋ฐ๊ธฐ์šฉ ๋ผ์šฐํŠธ

<Routes>
  <Route element={<PageLayout />}> // Layout
    <Route path="/privacy" element={<Privacy />} />
    <Route path="/tos" element={<Tos />} />
  </Route>
  <Route path="contact-us" element={<Contact />} />
</Routes>

// '/privacy' ๊ฒฝ๋กœ์—์„œ ๋ Œ๋”๋ง๋œ ๊ฒฐ๊ณผ๋ฌผ
<PageLayout>
  <Privacy />
</PageLayout>

LayoutRoute Component๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜์œ„ ๊ฒฝ๋กœ ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•  <Outlet> ์„ ์ถ”๊ฐ€ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Children์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

Last updated