React Router

์˜›์Šฌยท2022๋…„ 1์›” 10์ผ
0

REACT ๐Ÿ”ต

๋ชฉ๋ก ๋ณด๊ธฐ
13/16
post-thumbnail

ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์€ React Router์˜ ๊ณต์‹ ๋ฌธ์„œ ๋ฐ Youtube๋ฅผ ๊ณต๋ถ€ํ•œ ํ† ๋Œ€๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ˜น์‹œ๋ผ๋„ ์ž˜๋ชป๋œ ๋ถ€๋ถ„์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๊ผญ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š” ๐Ÿƒโ€โ™€๏ธ ๐Ÿƒโ€โ™€๏ธ

Non-React Websites

  • initial request
  • ์„œ๋ฒ„๊ฐ€ index.html๋ฅผ ๋ณด๋‚ด์คŒ
  • ๋งŒ์•ฝ์— ์ƒˆ๋กœ์šด ์„œ๋ธŒ ํŽ˜์ด์ง€ ํด๋ฆญ ์‹œ ํด๋ผ์ด์–ธํŠธ๋Š”
    request /path๋ฅผ ์š”์ฒญํ•จ.
  • ์„œ๋ฒ„๊ฐ€ path.html๋ฅผ ๋ณด๋‚ด์คŒ.

React Websites

  • initial request
  • ์„œ๋ฒ„๊ฐ€ index.html + ์ปดํŒŒ์ผ๋œ ๋ฆฌ์•กํŠธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ
  • ๋ฆฌ์•กํŠธ๋Š” ๋นˆ ํŽ˜์ด์ง€์— ์ปจํŠธ๋กค์„ ๊ฐ€์ง€๊ณ  ํŽ˜์ด์ง€๋ฅผ ์‚ฝ์ž…
  • ๋งŒ์•ฝ์— ์„œ๋ธŒ ํŽ˜์ด์ง€ ํด๋ฆญ ์‹œ, ๋ฆฌ์•กํŠธ๋Š” DOM์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.
    ( /path ์— ๋งž๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฝ์ž…ํ•จ)

React Router

- <BrowserRouter>

-<BrowserRouter>๋Š” ์›น ๋ธŒ๋ผ์šฐ์ €์— ์‚ฌ์šฉ๋œ๋‹ค.

  • <BrowserRouter>๋Š” History API ์ฒ˜๋Ÿผ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜์ง€ ์•Š๊ณ ๋„ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ์—ญํ• 
  • A <BrowserRouter> navigates using the browser's built-in history stack.

- <Routes> and <Route>

  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="expenses" element={<Expenses />} />
      <Route path="invoices" element={<Invoices />} />
    </Routes>
  </BrowserRouter>
  • <Route>๋Š” if๋ฌธ๊ณผ ๋น„์Šทํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด๋œ๋‹ค. ๋งŒ์•ฝ์— path๊ฐ€ ํ•ด๋‹น URL์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค๋ฉด ํ•ด๋‹น path์˜ element๋ฅผ ๋ Œ๋”๋ง ํ•˜๊ฒŒ ๋œ๋‹ค.
  • URL ๋ณ€๊ฒฝ ์‹œ, <Routes> ๋Š” ์ž์‹ ์˜ ๋ชจ๋“  children์„ ํ™•์ธํ•ด๋ณธ ํ›„ ํ•ด๋‹น๋˜๋Š” <Route> ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•œ๋‹ค.
import { Link } from "react-router-dom";

function Home() {
  return (
    <div>
      <h1>Home</h1>
      <nav>
        <Link to="/">Home</Link> |{" "}
        <Link to="about">About</Link>
      </nav>
    </div>
  );
  • ๋‹ค๋ฅธ ์›นํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” aํƒœ๊ทธ๋ฅผ ํŽ˜์ด์ง€ ์ด๋™์—†์ด ํŽ˜์ด์ง€๋ฅผ ๋ณ€ํ™˜ํ•˜๋„๋ก ํ•ด์คŒ
import * as React from "react";
import { NavLink } from "react-router-dom";

function NavList() {
  // This styling will be applied to a <NavLink> when the
  // route that it links to is currently selected.
  let activeStyle = {
    textDecoration: "underline"
  };

  let activeClassName = "underline"

  return (
    <nav>
      <ul>
        <li>
          <NavLink
            to="messages"
            style={({ isActive }) =>
              isActive ? activeStyle : undefined
            }
          >
            Messages
          </NavLink>
        </li>
        <li>
          <NavLink
            to="tasks"
            className={({ isActive }) =>
              isActive ? activeClassName : undefined
            }
          >
            Tasks
          </NavLink>
        </li>
      </ul>
    </nav>
  );
}
  • <Link>ํƒœ๊ทธ์™€ ๊ฒฐ์ด ๊ฐ™์Œ. ๋‹ค๋งŒ, <NavLink>์˜ ๊ฒฝ์šฐ ๋ณธ์ธ์ด activeํ•œ์ง€ ์•ˆํ•œ์ง€ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ์Œ!
  • <NavLink> ์‚ฌ์šฉ ์‹œ isActive๋ผ๋Š” ๊ฐ’์œผ๋กœ activeํ•œ์ง€ ์•ˆํ•œ์ง€ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ์Œ

- Nested Routes

  • ์ด๋ฆ„์ฒ˜๋Ÿผ ๋ผ์šฐํŠธ๊ฐ€ ์ค‘์ฒฉ๋˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • ์˜ˆ๋ฅผ ๋“ค๋ฉด, [ ๋ธ”๋กœ๊ทธ ํด๋ฆญ > ๋ธ”๋กœ๊ทธ ์ œ๋ชฉ ํด๋ฆญ > ๋ธ”๋กœ๊ทธ ๋‚ด์šฉ ] ์ฒ˜๋Ÿผ ๋งํฌ๊ฐ€ ์ค‘์ฒฉ๋˜๋Š” ํ˜•ํƒœ.
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route path="expenses" element={<Expenses />} />
        <Route path="invoices" element={<Invoices />} />
      </Route>
    </Routes>
  </BrowserRouter>,
  • ๋งŒ์•ฝ์— expenses ํŽ˜์ด์ง€๋กœ ์ด๋™ ์‹œ URL์˜ ๊ฒฝ์šฐ / + expenses
  • ์—ฌ๊ธฐ์„œ / ์˜ path๋ฅผ ๊ฐ€์ง„ ๋ถ€๋ชจ ๋ผ์šฐํŠธ๋ฅผ ๊ฐ€์ง„ App์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฉด์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ธ Expenses์™€ Invoices๋งŒ ๋ณ€๊ฒฝ๋œ๋‹ค ๐Ÿ‘‰ ์ด๊ฒŒ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ํ•˜๋‹จ์˜ <Outlet/>๊ฐœ๋…์„ ์•Œ์•„์•ผ ํ•จ.

- <Outlet>

export default function App() {
  return (
    <div>
      <h1>Bookkeeper</h1>
      <nav
        style={{
          borderBottom: "solid 1px",
          paddingBottom: "1rem"
        }}
      >
        <Link to="/invoices">Invoices</Link> |{" "}
        <Link to="/expenses">Expenses</Link>
      </nav>
      <Outlet />
    </div>
  );
}
  • ์ƒ๋‹จ์˜ nested routes๋ฅผ ๋ด์•ผ ์ดํ•ด๋จ! ๐Ÿ˜
  • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์ธ App์€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ ์–ด์ฃผ๊ณ , ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„์น˜์‹œํ‚ฌ ๋ถ€๋ถ„์— <Outlet/>์„ ์ ์–ด์ค€๋‹ค.
  • <Outlet/>์€ ๋‘ ์ž์‹์„ path๋ณ„๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  • 22.01.21 ์ถ”๊ฐ€ ) <Outlet/>์€ ์ž์‹ path์˜ ์ปดํฌ๋„ŒํŠธ ์˜์—ญ์„ ๋งˆํฌํ•˜๋Š” ๊ตฌ๊ฐ„์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค!

- "No Match" Routes path="*"

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
}
  • ํ•ด๋‹น ๋ผ์šฐํŠธ๋Š” ์–ด๋Š URL์ด๋“  ๋  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ€์žฅ ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— URL ์ค‘ ๋งค์น˜๋˜๋Š” ๋ผ์šฐํŠธ๊ฐ€ ์—†๋‹ค๋ฉด ํ•ด๋‹น URL์ด ์‚ฌ์šฉ๋  ๊ฒƒ์ด๋‹ค.

- Index Routes

<Route path="invoices" element={<Invoices />}>
  <Route index element={<InvoiceBase/>}/> ๐Ÿšฉ
  <Route path=":invoiceId" element={<Invoice />} />
</Route>
  • ๊นƒ๋ฐœ์ด ์žˆ๋Š” ๋ถ€๋ถ„์„ ๋ณด๋ฉด <Route/>์— path ๋Œ€์‹  index๋ผ๋Š” prop์ด ๋“ค์–ด๊ฐ€์žˆ๋‹ค.
  • ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ ๋ถ€๋ชจ์™€ ๊ฐ™์€ path๋ฅผ ๊ณต์œ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์‰ฝ๋‹ค.
  • ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” invoice์˜ base component๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ์ฆ‰, base component๊ฐ€ ๋ Œ๋”๋ง๋˜๊ณ  ์žˆ์ง€๋งŒ ๋งŒ์•ฝ์— ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ URL๋กœ ์ด๋™์‹œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ๋ผ์ง„๋‹ค.

- useNavigate

๐Ÿ‘‰ v5์—์„œ๋Š” useHistory ์—ˆ๋‹ค๊ฐ€ ๋ช…์นญ์ด ๋ณ€๊ฒฝ๋จ.

  • hook์˜ ์ด๋ฆ„์ฒ˜๋Ÿผ ํ™ˆํŽ˜์ด์ง€ ์œ„์น˜์— ๊ด€๋ จ๋จ
  • ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ useHistory๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
import { useNavigate } from "react-router-dom";

function SignupForm() {
  let navigate = useNavigate();

  async function handleSubmit(event) {
    event.preventDefault();
    await submitForm(event.target);
    navigate("../success", { replace: true });
  }

  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}
    1. ์ฒซ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ ๋งํฌ, ๋‘๋ฒˆ์งธ ๊ฐ’์œผ๋กœ option {replace, state} ๋ฅผ ๋„ฃ๋Š”๋‹ค.
    1. navigate(-1)์ฒ˜๋Ÿผ ์ž…๋ ฅ๊ฐ€๋Šฅ

- :style ๊ณผ useParams

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

function App() {
  return (
    <Routes>
       // 2๏ธโƒฃ 1๋ฒˆ์—์„œ ๋ฐ›์€ ๊ฐ’์€ param์ด ๋œ๋‹ค.
       // `:`ํ‚ค์›Œ๋“œ ์‚ฌ์šฉํ•˜์—ฌ param์ด ์žˆ๋‹ค๊ณ  ์•Œ๋ ค์คŒ.
      <Route path="invoices" element={<BlogList />}>
        <Route path=":id" element={<BlogDetails />} />
      </Route>
    </Routes>
  );
}

function BlogDetails() {
  // 3๏ธโƒฃ ํ•˜๋‹จ ๋ฌธ๊ตฌ๋ฅผ ํ†ตํ•ด id๋ฅผ Route์—์„œ ๋ฐ›์•„์˜ด.
  let { id } = useParams();
  return <h1>Blog {id}</h1>;
}

const BlogList = ({ blogs }) => {
  return (
    <div className="blog-list">
      <h2>All Blogs ๐Ÿ’™</h2>
      {blogs.map((blog) => (
        <div className="blog-preview" key={blog.id}>
          // 1๏ธโƒฃ ์ด๊ณณ์—์„œ param์— ์–ด๋–ค ๊ฐ’์ด ๋“ค์–ด๊ฐ€๋Š” ์ง€ ์„ค์ •.
          <Link to={`/blogs/${blog.id}`}>
            <h3>{blog.title}</h3>
            <p> Written By {blog.author} </p>
          </Link>
        </div>
      ))}
      <Outlet />
    </div>
  );
};
  1. ์›น ๋งํฌ์—์„œ parameter์˜ ๊ฐ’์„ ์„ค์ •ํ•˜๊ธฐ
  2. ํ•ด๋‹น ๊ฐ’์„ ๋ฐ›์•„์˜ฌ Route ์„ค์ • : ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ
  3. useParamsํ›…์„ ์‚ฌ์šฉํ•ด์„œ ๋ผ์šฐํŠธ์—์„œ ์„ค์ •ํ•œ params๋ฅผ ๋ฐ›์•„์˜ด.
import { useParams } from "react-router-dom";

export default function Invoice() {
  let params = useParams();
  return <h2>Invoice: {params.invoiceId}</h2>;
}
  • ์ด๋ ‡๊ฒŒ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ!

- useSearchParams

  • ๊ธฐ๋ณธ์ ์œผ๋กœ URL์„ ๋‚˜๋ˆŒ ๋•Œ /๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, search params์˜ ๊ฒฝ์šฐ ?๋ฅผ ์‚ฌ์šฉํ•จ
  • ์˜ˆ์‹œ : "/login?success=1"
    ๐Ÿ‘‰ ์‹ค์Šต ํ›„ ๋‹ค์‹œ ์ •๋ฆฌ ์˜ˆ์ •

- useRoutes

  • <Routes>์™€ <Route>๋Œ€์‹  ์‚ฌ์šฉ
  • the fuctional equivalent of <Routes>
  • uses JS objects instead of <Route> elements
  • don't require JSX
import * as React from "react";
import { useRoutes } from "react-router-dom";

function App() {
  let element = useRoutes([
    {
      path: "/",
      element: <Dashboard />,
      children: [
        {
          path: "messages",
          element: <DashboardMessages />
        },
        { path: "tasks", element: <DashboardTasks /> }
      ]
    },
    { path: "team", element: <AboutPage /> }
  ]);

  return element;
}
profile
์›น ํผ๋ธ”๋ฆฌ์…”์ž…๋‹ˆ๋‹ค๐Ÿ’“

0๊ฐœ์˜ ๋Œ“๊ธ€