React Router

ํ•™์Šต ํ‚ค์›Œ๋“œ

  • Router

  • React Router

    • BrowserRouter

      • history API

    • Routes

    • Route

    • MemoryRouter

  • ๋™์  ๋ผ์šฐํŒ…

    • URL Parameter

    • useParams

    • Query String

    • useSearchParams

  • ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ ๊ฐ„์— ๋ฐ์ดํ„ฐ ํŒจํ‚ท์„ ์ „์†กํ•˜๋Š” ๋„คํŠธ์›Œํฌ ์žฅ์น˜๋‹ค.

  • ์ฆ‰, ์„œ๋กœ ๋‹ค๋ฅธ ๋„คํŠธ์›Œํฌ ๊ฐ„์— ์ตœ์ ์˜ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ™œ์šฉํ•ด ์ค‘๊ณ„ ์—ญํ• ์„ ํ•ด์ฃผ๋Š” ์žฅ์น˜๋‹ค.

Routing Diagram

React Router

  • React์—์„œ ์ฃผ์†Œ(URL)์— ๋”ฐ๋ฅธ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • Context API๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๐Ÿค” ์™œ React Router ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ผ์šฐํŒ…์ด๋ผ๋Š” ๊ฐœ๋…์€ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ URL์— ๋”ฐ๋ผ ์•Œ๋งž๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋•Œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ธ”๋กœ๊ทธ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด, ํ™ˆ, ํฌ์ŠคํŠธ ๋ชฉ๋ก, ํฌ์ŠคํŠธ, ๊ธ€์“ฐ๊ธฐ ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€๋“ค์ด ์žˆ๋‹ค. ๋˜ํ•œ ์ด ํŽ˜์ด์ง€๋“ค์— ๋”ฐ๋ผ ์ฃผ์†Œ(URL)๋„ ๋งŒ๋“ค์–ด์ค˜์•ผ ํ•œ๋‹ค. ์ฃผ์†Œ๊ฐ€ ์žˆ์–ด์•ผ, ์œ ์ €๋“ค์ด ๋ถ๋งˆํฌ๋„ ํ•  ์ˆ˜ ์žˆ๊ณ  ์„œ๋น„์Šค์— ๊ตฌ๊ธ€์„ ํ†ตํ•ด ์œ ์ž…๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋กœ ๊ตฌ์„ฑ๋œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ๋•Œ ํŽ˜์ด์ง€๋ณ„๋กœ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋ถ„๋ฆฌํ•ด๊ฐ€๋ฉด์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ ๋ผ์šฐํŒ… ์‹œ์Šคํ…œ(React Router)์ด๋‹ค.

๐Ÿค– React Router ์˜ ์—ญํ™œ

์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ € ์ฃผ์†Œ์ฐฝ์˜ ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ์•Œ๋งž๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ์ดํ›„ ๋งํฌ๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ ๋  ๋•Œ ์„œ๋ฒ„์— ๋‹ค๋ฅธ ํŽ˜์ด์ง€์˜ html์„ ์ƒˆ๋กœ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ธŒ๋ผ์šฐ์ €์˜ History API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ์ฐฝ์˜ ๊ฐ’๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  ๊ธฐ์กด์— ํŽ˜์ด์ง€์— ๋„์› ๋˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ผ์šฐํŒ… ์„ค์ •์— ๋”ฐ๋ผ ๋˜ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ฒŒ ๋œ๋‹ค.

React Router ์‚ฌ์šฉ๋ฒ•

โš™๏ธ React Router ์„ค์น˜

npm i react-router-dom

  • HTML5์˜ History API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š๊ณ ๋„ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ํ˜„์žฌ ์ฃผ์†Œ์˜ ๊ฒฝ๋กœ์— ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ฃผ๋Š” ์—ญํ™œ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ๋ผ์šฐํŒ…์„ ์ง„ํ–‰ํ•  ์ปดํฌ๋„ŒํŠธ ์ƒ์œ„์— BrowserRouter ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฐ์‹ธ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

๐Ÿ“– History API

history ์ „์—ญ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ € ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—์„œ ํŽ˜์ด์ง€ ๋กœ๋”ฉ์„ ํ•˜๋ฉด, ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ฐ–๋Š”๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ํžˆ์Šคํ† ๋ฆฌ๋ฅผ stack์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค. ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ๋Š” ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ๋•Œ ๋งˆ๋‹ค ์Œ“์ด๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ๋’ค๋กœ๊ฐ€๊ธฐ ๋˜๋Š” ์•ž์œผ๋กœ ๊ฐ€๊ธฐ ๊ฐ™์€ ์ด๋™์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

โ‡’ "์–ด๋–ค ํŽ˜์ด์ง€๋ฅผ ํƒ์ƒ‰ํ–ˆ๋Š”์ง€์— ๋Œ€ํ•ด์„œ history๋ฅผ ์Œ“๋Š” ๊ฒƒ" ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿค” ์™œ History API๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๊ฐ€?

  • React๋Š” SPA์˜ ๊ธฐ๋ฐ˜์ด๋‹ค. ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋”ฉ์ด ๋˜์–ด ๋ณ€๊ฒฝ๋˜๋Š”๊ฒƒ ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธ(๋ฆฌ๋ Œ๋”๋ง)ํ•ด์ค€๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” ํ™”๋ฉด ์ด๋™์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ ‡๊ธฐ์— History API๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ํ™”๋ฉด ์ด๋™ ์—†์ด URL์„ ์—…๋ฐ์ดํŠธ ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

Routes & Route

  • Routes์™€ Route๋Š” React Router v6๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ฐœ๋…์ด๋‹ค.

  • ๋ชจ๋“  Route์˜ ์ƒ์œ„ ๊ฒฝ๋กœ์— ์กด์žฌํ•ด์•ผ ํ•˜๋ฉฐ, location ๋ณ€๊ฒฝ ์‹œ ํ•˜์œ„์— ์žˆ๋Š” ๋ชจ๋“  Route๋ฅผ ์กฐํšŒํ•ด ํ˜„์žฌ location๊ณผ ๋งž๋Š” Route๋ฅผ ์ฐพ์•„์ค€๋‹ค.

  • ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ €์˜ location(window.location.path ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค)์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ element๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.

<Route path="/๊ฒฝ๋กœ" element={<Component />} />

  • ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์ด ์•„๋‹Œ ๊ณณ์—์„œ ReactRouter๊ฐ€ ํฌํ•จ๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

  • MemoryRouter๋Š” ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์•„, ์ฃผ์†Œ๋ฅผ ๋”ฐ๋กœ ์žก์•„์ฃผ์–ด์•ผ ํ•œ๋‹ค.

<MemoryRouter initialEntries={['/๊ฒฝ๋กœ']} >

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป React Router ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ

// main.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';

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

import App from './App';

function main() {
  const container = document.getElementById('root');
  if (!container) {
    return;
  }

  const root = ReactDOM.createRoot(container);
  root.render(
    <React.StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </React.StrictMode>
  );
}

main();
// App.tsx

import { Routes, Route } from 'react-router-dom';

import Homepage from './pages/HomePage';
import AboutPage from './pages/AboutPage';

import Header from './components/Header';
import Footer from './components/Footer';

export default function App() {
  return (
    <div>
      <Header />
      <main>
        <Routes>
          <Route path="/" element={<Homepage />} />
          <Route path="/about" element={<AboutPage />} />
        </Routes>
      </main>
      <Footer />
    </div>
  );
}
// App.test.tsx

import { render, screen } from '@testing-library/react';

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

import App from './App';


describe('App', () => {

  function renderApp(path: string) {
    render((
    <MemoryRouter initialEntries={[path]}> 
      <App />
    </MemoryRouter>
    ));
  }
 
  context('when the current path is โ€œ/โ€', () => {
    it('renders the home page', () => {
    renderApp('/');

    screen.getByText(/Hello/);
    });
  });
 
  context('when the current path is โ€œ/aboutโ€', () => {
    it('renders the about page', () => {
    renderApp('/about');

    screen.getByText(/About/);
    });
  });
});

๋™์  ๋ผ์šฐํŒ…

  • ๋™์  Routing์€ ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ์ •ํ•ด๋‘์ง€ ์•Š๊ณ  ๋™์ ์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

  • ๋ผ์šฐํŠธ์˜ ๊ฒฝ๋กœ์— ํŠน์ • ๊ฐ’์„ ๋„ฃ์–ด ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ฒƒ

๐Ÿค” ๋™์  ๋ผ์šฐํŒ…์ด ํ•„์š”ํ•œ ์ด์œ ๋Š”?

React Router ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฏธ๋ฆฌ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉํ•  ๊ฒฝ๋กœ๋“ค๊ณผ ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•ด๋‘”๋‹ค. ํ•˜์ง€๋งŒ ๋ณต์žกํ•˜๊ณ  ๊ทœ๋ชจ๊ฐ€ ํฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹๋งŒ์œผ๋กœ๋Š” ์ฒ˜๋ฆฌํ•˜๊ธฐ ํž˜๋“  ์ž‘์—…์ด ์กด์žฌํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์‡ผํ•‘๋ชฐ์—๋Š” ๋‹ค์–‘ํ•œ ์ƒํ’ˆ์ด ์กด์žฌํ•˜๊ณ , ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ๊ฐ€ ์žˆ๊ณ , ๋˜ํ•œ ์ƒํ’ˆ ์ƒ์„ธํŽ˜์ด์ง€๋„ ์กด์žฌํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ƒํ’ˆ๋ฆฌ์ŠคํŠธ์—์„œ ์„ ํƒํ•œ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€์— ์ ‘๊ทผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

๐Ÿ’ก ํŠน์ • ๊ทœ์น™์„ ๋งŒ๋“ค๊ณ , ๊ทธ ๊ทœ์น™๊ณผ ๋ถ€ํ•ฉํ•˜๋Š” URL์ด ์žˆ์„ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น element๋ฅผ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

URL Parameter

  • /:๊ฐ’ ํ˜•ํƒœ๋กœ ๋™์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

  • : ๊ธฐํ˜ธ ๋’ค์— ๋ถ™๋Š” ๋ฌธ์ž์—ด์ด Path Parameter ์ด๋‹ค.

  • Path Parameter ๋Š” URL์— ์žˆ๋Š” ๊ฐ’์„ ๋งˆ์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜(Parameter)์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • Path parameter๋ฅผ ์ด์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•˜๋”๋ผ๋„, ํฐ ํ‹€์€ ๋™์ผํ•˜๋˜ ๋‹ค๋ฅธ UI๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

function App() {

  return (
    <Layout>
      <Routes>
        <Route path={'/'} element={<Home/>}></Route>
        <Route path={'/search'} element={<Search/>}></Route>
        <Route path={'/country/:code'} element={<Country/>}></Route>
        <Route path={'*'} element={<NotFound/>}></Route>
      </Routes>
    </Layout>
  );
}
export default App

โš™๏ธ useParams

  • URL Params์˜ ๊ฐ’์„ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • key : Route ์—์„œ ์„ค์ •ํ•œ Path Parameter์˜ ์ด๋ฆ„

  • value : Route์—์„œ ์„ค์ •ํ•œ Path Parameter์— ์‹ค์ œ๋กœ ์ „๋‹ฌ๋œ ๊ฐ’

/post/:id๋กœ path๋ฅผ ์„ค์ •ํ–ˆ์„ ๋•Œ, ์œ ์ €๊ฐ€ /post/1๋กœ ์ ‘์†ํ•  ๊ฒฝ์šฐ useParams๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด์˜ key๋Š” id์ด๊ณ , value๋Š” 1์ด๋‹ค.

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

export default function Country(){
   const params = useParams();
   console.log(params); // {code : 'KOR'}
   return(
      <div>
         Country! {params.code}
      </div>
   );
}

QueryString

  • URL์— ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ํฌํ•จ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค. ํŠน๋ณ„ํ•œ ์„ค์ •์„ ํ•  ํ•„์š”๋Š” ์—†๋‹ค.

    • Link ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ : <Link to="/list?sort=popular" />

    • navigate ํ•จ์ˆ˜ ์˜ˆ์‹œ : navigate("/list?sort=popular")

โš™๏ธ useSearchParams

  • QueryString (์˜ˆ : ?sort=popular&sort=latest) ์—์„œ ์›ํ•˜๋Š” ๊ฐ’๋งŒ ๊บผ๋‚ด์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” Hook

const [searchParams, setSearchParams] = useSearchParams();
  • searchParams.get(key) : ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์—์„œ ํŠน์ • key์˜ value ๊ฐ’ ๋ฐ˜ํ™˜ (ํ•˜๋‚˜๋งŒ)

  • searchParams.getAll(key) : ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์—์„œ ํŠน์ • key์˜ ๋ชจ๋“  value ๊ฐ’์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜

  • searchParams.toString() : ๊ฐ์ฒด ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜

๐Ÿ”— ์ฐธ๊ณ 

Last updated