๐Ÿ‘ฉ‍๐Ÿ’ป/React

[react-router-dom] React Router v6์— ๋„์ž…๋œ ์ƒˆ๋กœ์šด Navigate API - Redirect ๋Œ€์ฒดํ•˜๊ธฐ

ํ•œ๋‚˜ 2022. 2. 10. 01:21

 

์ตœ๊ทผ์— react-router-dom์„ ์“ฐ๋ ค๊ณ  ๋ณด๋‹ˆ ๋ฒ„์ „ ์—…์ด ๋˜์–ด์„œ ๊ธฐ์กด์— ์•Œ๋˜ v5์˜ ์‚ฌํ•ญ๋“ค์ด ๋งŽ์ด ๋ฐ”๋€ ๊ฒƒ์„ ์•Œ์•˜๋‹ค. ๊ฐ€๋ น Switch๊ฐ€ Routes๋กœ, Redirect๊ฐ€ Navigate ๋“ฑ์œผ๋กœ ๋Œ€์ฒด๋˜๋Š” ๊ฒƒ์ด ์žˆ์—ˆ๋Š”๋ฐ, ์ข€ ๋” ํ™•์‹คํžˆ ์ดํ•ด ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ๋˜๊ธฐ๋„ ํ–ˆ๊ณ , ๊ธฐ์กด rediect ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Navigate API๊ฐ€ ๋„์ž…๋˜๊ธฐ๋„ ํ–ˆ๋‹ค. ์•„๋ž˜๋Š” ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฝ์œผ๋ฉด์„œ ํ•„์š”ํ•œ ๋‚ด์šฉ๋งŒ ์ •๋ฆฌํ•ด๋ณด์•˜๋Š”๋ฐ, ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ด๊ณณ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๊ณต์‹ ๋ฌธ์„œ์—์„œ ๋งํ•˜๊ธธ, ์šฐ์„  v5์™€์˜ ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ํŒจํ‚ค์ง€๋Š” ์กฐ๊ธˆ ์‹œ์ผ์ด ๊ฑธ๋ฆด ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ํ•œ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€๋˜๋Š” routes๊ฐ€ ์žˆ์„ ๊ฒƒ์ธ์ง€, ๋ณ€๊ฒฝ๋  ๊ฒƒ์ด ์žˆ์„์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ..!

We recommend waiting for the backwards compatibility package to be released before upgrading apps that have more than a few routes.

๊ฐœ์š”

์‹ ๊ทœ ๋ฆฌ์•กํŠธ ์—…๋ฐ์ดํŠธ์— ๋งž์ถฐ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์‹ ๊ทœ ๋„์ž…๋˜์—ˆ๋‹ค. ์•ž์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ v6๋Š” v4, 5์— ๋น„ํ•ด์„œ ๋งŽ์€ ๋ณ€ํ™”๊ฐ€ ์žˆ์—ˆ๋‹ค. ์˜ˆ์ „ ์ฝ”๋“œ ์ค‘ ์ผ๋ถ€๋ฅผ ๋ฒ„์ „์—…์„ ํ•ด๋ณด๋ฉด์„œ ์–ด๋–ป๊ฒŒ ๋‹ฌ๋ผ์กŒ๋Š”์ง€ ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์•„๋ž˜๋Š” ์ด์ „ ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์˜ package.json. react-router-dom์ด 6 ๋ฒ„์ „ ์ด์ „์ด๋ผ๋ฉด ์—…๊ทธ๋ ˆ์ด๋“œ ํ•ด๋ด„์งํ•˜๋‹ค. 

    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "axios": "^0.21.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.0.1"

React v16.8๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ

๋ฆฌ์•กํŠธ๋Š” ์ด๋ฏธ ๋ฒ„์ „ 17์„ ์“ฐ๊ณ  ์žˆ์—ˆ๋‹ค. React Router v6๋Š” ๋ฆฌ์•กํŠธ ํ›…์„ ๋งŽ์ด ์“ฐ๊ณ  ์žˆ์–ด์„œ, 16.8 ๋ฒ„์ „ ์ด์ƒ์„ ๊ถŒ๊ณ ํ•˜๊ณ  ์žˆ๋‹ค.

React Router v5.1๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ธฐ

๋งŒ์ผ 5.1 ๋ฒ„์ „ ์ด์ „์˜ ๊ฒƒ์„ ์“ฐ๊ณ  ์žˆ์—ˆ๋‹ค๋ฉด, ์šฐ์„  5.1 ๋ฒ„์ „์œผ๋กœ ๋จผ์ € ์—…๊ทธ๋ ˆ์ด๋“œ ํ•˜๊ณ , ๊ทธ ์ดํ›„์— v6๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ฒƒ์ด ์ˆ˜์›”ํ•˜๋‹ค๊ณ  ์„ค๋ช…ํ•˜๊ธธ๋ž˜ ํ•œ ๋ฒˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ธฐ๋กœ ํ–ˆ๋‹ค. ์ด๋Ÿฐ ์ €๋Ÿฐ ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋‹ต๋ณ€๋“ค์„ ๋ณด๋ฉด ์—ฌ๋Ÿฌ ๋ฒ„์ „์˜ ์ฝ”๋“œ๋ฅผ ์„ž์–ด์„œ ๋ณด๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ๋ถ„ํ•  ์ค„ ์•Œ๋ฉด ํ˜„์žฌ ์ฝ”๋“œ ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์šฉํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฌ์šธ ๊ฒƒ์ด๋‹ค. 

// v5.1 ์ด์ „์˜ v4 ๋˜๋Š” v5

function User({ id }) {
  // ...
}

function App() {
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route
        path="/users/:id"
        render={({ match }) => (
          <User id={match.params.id} />
        )}
      />
    </Switch>
  );
}

render props๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฃจ์—ˆ๋‹ค๋ฉด, v5์—์„œ๋Š” children props๋ฅผ ํ†ตํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „๋‹ฌํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  usePramas ํ›…์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜๋Š” params ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.


// v5.1 preferred style
function User() {
  let { id } = useParams();
  // ...
}

function App() {
  return (
    <Switch>
      <Route exact path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      {/* Can also use a named `children` prop */}
      <Route path="/users/:id" children={<User />} />
    </Switch>
  );
}

v6๋ฅผ ํฌํ•จํ•ด v5๋Š” ์ด๋Ÿฐ ์‹์˜ ์ปดํฌ๋„ŒํŠธ ๋Œ€์‹  elements ๋ฅผ ์“ฐ๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•œ๋‹ค.

์ฆ‰, ์ด๋ฒˆ ๋ฒ„์ „์—์„œ๋Š”

  • <Route render>๋‚˜ <Route component> ๋Œ€์‹  <Route children>์„ ์“ธ ๊ฒƒ
  • location, params ๊ฐ™์€ state์— ์ ‘๊ทผํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” hook์„ ์“ธ ๊ฒƒ
  • <Switch> ๋‚ด๋ถ€์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” <Route>๋Š” ๋ชจ๋‘ <Switch> ์•ˆ์— ์ œ๋Œ€๋กœ ์œ„์น˜ํ•˜๋„๋ก ํ•˜๊ฑฐ๋‚˜ useRouteMatch๋กœ ๋Œ€์ฒดํ•  ๊ฒƒ.

React Route v6์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•˜๊ธฐ

<Switch> ์•ˆ์— ์žˆ๋Š” <Redirect> ์ œ๊ฑฐํ•˜๊ธฐ : <Navigate> API

๊ธฐ์กด์—๋Š” Redirect๋ฅผ ์›ํ•  ๋•Œ ์•„๋งˆ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์„ ๊ฒƒ์ด๋‹ค.

import { Switch, Route, Redirect } from "react-router-dom";

function App() {
  return (
    <Switch>
      <Route path="/home">
        <HomePage />
      </Route>
      <Redirect from="/" to="/home" />
    </Switch>
  );
}

์ฆ‰, ๋ธŒ๋ผ์šฐ์ €๋‚˜ ๋ฆฌ์•กํŠธ์˜ Node.js ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์œ ์ €๊ฐ€ ์•ฑ์˜ / URL์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ, ์ž๋™์œผ๋กœ /home์œผ๋กœ ์ด๋™์‹œ์ผœ์ฃผ๋Š” ์ฝ”๋“œ์ด๋‹ค. ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ <Redirect>๊ฐ€ ํ•˜๋Š” ์—ญํ• ์€ ์ดˆ๊ธฐ ๋ Œ๋” ์‹œ์— history.replaceState()๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด์Šˆ๊ฐ€ ๋ช‡ ๊ฐ€์ง€ ์žˆ๋Š”๋ฐ, ๊ฐ€๋ น ๋ธŒ๋ผ์šฐ์ €์—์„œ์˜ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋Š” ์‚ฌ์‹ค์ƒ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํ•œ๋‹ค. ์›๋ž˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ–ˆ๋˜ URL์— ๋Œ€ํ•ด์„œ๋Š” ์„œ๋ฒ„๊ฐ€ status code 200์œผ๋กœ, ์œ ํšจํ•œ HTML ํŽ˜์ด์ง€๋ฅผ ์„œ๋ธŒํ•˜๊ฒŒ ๋œ๋‹ค. ๋งŒ์ผ ๊ฒ€์ƒ‰์—”์ง„ ํฌ๋กค๋Ÿฌ๋กœ ๋“ค์–ด์˜จ ์š”์ฒญ์ด์—ˆ๋‹ค๋ฉด, ์œ ํšจํ•œ HTML์ด ์„œ๋ธŒ๋˜๋‹ˆ, ํ•ด๋‹น ์ธ๋ฑ์Šค๊ฐ€ ์ง„์งœ ์ธ๋ฑ์Šค ํŽ˜์ด์ง€๋กœ ์ธ์‹ํ•  ๊ฒƒ์ด๋‹ค. ์˜๋„๋Œ€๋กœ redirectํ•ด์„œ ๋ณด๋‚ธ ํŽ˜์ด์ง€์— ๋Œ€ํ•ด์„œ๋Š” ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์œผ๋ฏ€๋กœ SEO์— ์ข‹์ง€ ๋ชปํ•˜๋‹ค.

 

ํ˜น์‹œ ์„œ๋ฒ„ ์ƒ์—์„œ์˜ ์ดˆ๊ธฐ ๋ Œ๋” ์‹œ์˜ redirect ์ด์Šˆ์— ๋Œ€ํ•ด์„œ๋Š” ์ด ๋ฌธ์„œ๋ฅผ ๋” ์ฝ์–ด๋ณด๋ฉด ์ข‹๋‹ค. ์œ„ ๋‚ด์šฉ๋„ ๋ฌธ์„œ์—์„œ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. 

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด React๋ฅผ ๋ Œ๋”ํ•˜๊ธฐ ์ „์— ๋ฐ”๋กœ ์„œ๋ฒ„ ์ƒ์—์„œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๊ณ , ์ ์ ˆํ•œ status code๋ฅผ ๋ณด๋‚ด๋ฉด ๋œ๋‹ค. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ์•ฑ์ด ์•„๋‹ˆ๋ผ๋ฉด ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์‹œ์— ์•„๋ž˜์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜ ์žˆ๋‹ค.

 

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

function App() {
  return (
    <Routes>
      <Route path="/home" element={<Home />} />
      <Route path="/" element={<Navigate replace to="/home" />} />
    </Routes>
  );
}

์–ด๋””๊นŒ์ง€๋‚˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ์•ฑ์ด ์•„๋‹ ๋•Œ ์“ธ ์ˆ˜ ์žˆ๋‹ค. navigation์€ React.useEffect()๋กœ ์ธํ•ด ์ผ์–ด๋‚˜๋Š” ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด๋ผ๋Š” ์ !

 

<Navigate> ์—˜๋ฆฌ๋จผํŠธ๋Š” useNavigate() ํ›…์˜ declarative version์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด์ „ ๋ฒ„์ „์—์„œ <Switch> ๋ฐ”๊นฅ์˜ <Redirect>๋ฅผ ๋Œ€์ฒดํ•  ๋ชฉ์ ์œผ๋กœ ์ข‹๋‹ค.


<Navigate replace>์—์„œ replace prop์€ history.replaceState()๋ฅผ ์“ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฌป๋Š”๋‹ค.