5 min read

React Router 7์—์„œ ๋˜‘๋˜‘ํ•œ ๋’ค๋กœ๊ฐ€๊ธฐ ๊ตฌํ˜„ํ•˜๊ธฐ

Table of Contents

๋“ค์–ด๊ฐ€๋ฉฐ

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด โ€œ๋’ค๋กœ๊ฐ€๊ธฐโ€ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฒ„ํŠผ์€ ๊ฑฐ์˜ ํ•„์ˆ˜์ฃ .

๊ทธ๋Ÿฐ๋ฐ ๋‹จ์ˆœํžˆ navigate(-1)๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. URL์„ ํ†ตํ•ด ์ƒ์„ธ ํŽ˜์ด์ง€์— ์ง์ ‘ ์ ‘๊ทผํ•œ ๊ฒฝ์šฐ, ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ธŒ๋ผ์šฐ์ € ๋นˆ ํŽ˜์ด์ง€๋‚˜ ์ด์ „์— ๋จธ๋ฌผ๋ €๋˜ ์ „ํ˜€ ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ๋กœ ์ด๋™ํ•˜๊ฒŒ ๋˜๊ฑฐ๋“ ์š”.

์ด ๊ธ€์—์„œ๋Š” React Router 7์˜ location.key๋ฅผ ํ™œ์šฉํ•ด์„œ, ์ƒํ™ฉ์— ๋งž๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๋˜‘๋˜‘ํ•œ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ์ƒํ™ฉ

์ œ๊ฐ€ ๋งŒ๋“ค๊ณ  ์žˆ๋˜ ์„œ๋น„์Šค์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค:

  • /books - ์ฑ… ๋ชฉ๋ก ํŽ˜์ด์ง€
  • /books/:id - ์ฑ… ์ƒ์„ธ ํŽ˜์ด์ง€

์‹œ๋‚˜๋ฆฌ์˜ค 1. ์ •์ƒ์ ์ธ ํ๋ฆ„

๋ชฉ๋ก ํŽ˜์ด์ง€(/books)
  โ†’ ์ƒ์„ธ ํŽ˜์ด์ง€ ํด๋ฆญ(/books/123)
  โ†’ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ
  โ†’ ๋ชฉ๋ก ํŽ˜์ด์ง€(/books)๋กœ ๋ณต๊ท€ โœ…

์ด ๊ฒฝ์šฐ๋Š” navigate(-1)๋งŒ์œผ๋กœ๋„ ์™„๋ฒฝํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค 2. ์ง์ ‘ ์ ‘๊ทผ

URL์„ ํ†ตํ•ด ์ƒ์„ธ ํŽ˜์ด์ง€ ์ง์ ‘ ์ ‘๊ทผ(/books/123)
  โ†’ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ
  โ†’ ??? โŒ

๋ฌธ์ œ๋Š” ์ด ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ์— ๋ญ๊ฐ€ ์žˆ๋Š”์ง€์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

  • ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์—์„œ ๋งํฌ๋ฅผ ํƒ€๊ณ  ์™”๋‹ค๋ฉด โ†’ ๊ทธ ์‚ฌ์ดํŠธ๋กœ ๋Œ์•„๊ฐ
  • ์ฃผ์†Œ์ฐฝ์— URL์„ ์ง์ ‘ ์ž…๋ ฅํ–ˆ๋‹ค๋ฉด โ†’ ๋ธŒ๋ผ์šฐ์ € ๋นˆ ํŽ˜์ด์ง€(about:blank)

์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” โ€œ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ๋ˆŒ๋ €๋Š”๋ฐ ์„œ๋น„์Šค๋ฅผ ๋ฒ—์–ด๋‚˜๋ฒ„๋ฆฐโ€ ๋ ์šฉํ•˜๋Š” ๊ฒฝํ—˜์ด ๋ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ์ฑ…: location.key๋ฅผ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ ๋„ค๋น„๊ฒŒ์ด์…˜

React Router๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋กœ location.key์ž…๋‹ˆ๋‹ค.

import { useNavigate, useLocation } from "react-router";

export default function BookDetail() {
  const navigate = useNavigate();
  const location = useLocation();

  const handleBackClick = () => {
    if (location.key === "default") {
      // ์ง์ ‘ ์ ‘๊ทผํ•œ ๊ฒฝ์šฐ: ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™
      navigate("/books");
    } else {
      // ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ: ๋’ค๋กœ๊ฐ€๊ธฐ
      navigate(-1);
    }
  };

  return (
    <div>
      <button onClick={handleBackClick}>โ† ๋’ค๋กœ๊ฐ€๊ธฐ</button>
      <h1>์ฑ… ์ƒ์„ธ ์ •๋ณด</h1>
      {/* ... */}
    </div>
  );
}

์ด์ œ ๋‘ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชจ๋‘ ์™„๋ฒฝํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ชฉ๋ก์—์„œ ์™”๋‹ค๋ฉด โ†’ navigate(-1)๋กœ ๋ชฉ๋ก์œผ๋กœ ๋ณต๊ท€
  • URL๋กœ ์ง์ ‘ ์™”๋‹ค๋ฉด โ†’ navigate("/books")๋กœ ๋ชฉ๋ก์œผ๋กœ ์ด๋™

location.key๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

location.key๋Š” React Router๊ฐ€ ๊ฐ location(์œ„์น˜)์— ๋ถ€์—ฌํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž์ž…๋‹ˆ๋‹ค.

location ๊ฐ์ฒด์˜ ๊ตฌ์กฐ

interface Location {
  pathname: string; // "/books/123"
  search: string; // "?sort=title"
  hash: string; // "#review"
  state: any; // ์ปค์Šคํ…€ ์ƒํƒœ
  key: string; // ๊ณ ์œ  ์‹๋ณ„์ž (์ฃผ๋ชฉ)
}

key์˜ ํŠน๋ณ„ํ•œ ์ 

This value is always โ€˜defaultโ€™ on the initial location.

location.key๋Š” ์ตœ์ดˆ ์ง„์ž… ์‹œ์— ํ•ญ์ƒ โ€˜defaultโ€™ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

// ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์—ด๊ณ  ์ง์ ‘ URL ์ž…๋ ฅ
location.key; // "default"

// ์•ฑ ๋‚ด์—์„œ navigate()๋กœ ์ด๋™
location.key; // "abc123" (๋žœ๋คํ•œ ๊ณ ์œ  ๋ฌธ์ž์—ด)

key๋Š” ์–ธ์ œ ์ƒ์„ฑ๋˜๋‚˜?

React Router๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ์ƒˆ๋กœ์šด key๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  1. <NavLink>, <Link> ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋™
  2. navigate() ํ•จ์ˆ˜ ํ˜ธ์ถœ
  3. <Form> ์ œ์ถœ ํ›„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  4. ๋ธŒ๋ผ์šฐ์ € ๋’ค๋กœ๊ฐ€๊ธฐ/์•ž์œผ๋กœ๊ฐ€๊ธฐ (์ด๋ฏธ ์กด์žฌํ•˜๋Š” key ์žฌ์‚ฌ์šฉ)

๋ฐ˜๋Œ€๋กœ ๋‹ค์Œ์˜ ๊ฒฝ์šฐ key๋Š” โ€œdefaultโ€์ž…๋‹ˆ๋‹ค.

  1. ๋ธŒ๋ผ์šฐ์ € ์ฃผ์†Œ์ฐฝ์— URL ์ง์ ‘ ์ž…๋ ฅ
  2. ์™ธ๋ถ€ ๋งํฌ์—์„œ ์ ‘๊ทผ
  3. ๋ถ๋งˆํฌ์—์„œ ์ ‘๊ทผ
  4. ์ƒˆ ํƒญ/์ฐฝ์œผ๋กœ ์—ด๊ธฐ

ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ๊ณผ key

React Router์˜ ํžˆ์Šคํ† ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋ฉด key์˜ ์—ญํ• ์ด ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.

์ •์ƒ ํ๋ฆ„์˜ ํžˆ์Šคํ† ๋ฆฌ

1. ์•ฑ ์‹œ์ž‘ (/)
   key: "default"
   ํžˆ์Šคํ† ๋ฆฌ: [/]

2. ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ (/books)
   key: "aaa111" (๋žœ๋ค ๋ฌธ์ž์—ด)
   ํžˆ์Šคํ† ๋ฆฌ: [/, /books]

3. ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ (/books/123)
   key: "bbb222"
   ํžˆ์Šคํ† ๋ฆฌ: [/, /books, /books/123]

4. ๋’ค๋กœ๊ฐ€๊ธฐ ์‹คํ–‰
   โ†’ navigate(-1)
   โ†’ ํžˆ์Šคํ† ๋ฆฌ์—์„œ ํ•œ ์นธ ๋’ค๋กœ
   โ†’ /books (key: "aaa111") ๋ณต๊ท€

์ด ๊ฒฝ์šฐ location.key๋Š” โ€œbbb222โ€ ๊ฐ™์€ ๊ฐ’์ด๋ฏ€๋กœ, navigate(-1)์ด ์•ˆ์ „ํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ง์ ‘ ์ ‘๊ทผ์˜ ํžˆ์Šคํ† ๋ฆฌ

1. URL๋กœ ์ง์ ‘ ์ ‘๊ทผ (/books/123)
   key: "default"
   ํžˆ์Šคํ† ๋ฆฌ: [/books/123]

2. ๋’ค๋กœ๊ฐ€๊ธฐ ์‹คํ–‰
   โ†’ navigate(-1) ์‹œ๋„
   โ†’ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋น„์–ด์žˆ์Œ
   โ†’ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ณธ ๋™์ž‘ (์ด์ „ ์‚ฌ์ดํŠธ/๋นˆ ํŽ˜์ด์ง€)

์ด ๊ฒฝ์šฐ location.key === "default"์ด๋ฏ€๋กœ, ์šฐ๋ฆฌ๋Š” navigate("/books")๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

1. HashRouter์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š์Œ

location.key๋Š” BrowserRouter์—์„œ ์ง€์›๋ฉ๋‹ˆ๋‹ค. HashRouter๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ด ํŒจํ„ด์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2. replace๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

navigate(path, { replace: true })๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ํ˜„์žฌ ํ•ญ๋ชฉ์„ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ key๋Š” ๋ณ€๊ฒฝ๋˜์ง€๋งŒ ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด๋Š” ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค.

// ํžˆ์Šคํ† ๋ฆฌ: [/, /books]

navigate("/books/123", { replace: true });

// ํžˆ์Šคํ† ๋ฆฌ: [/, /books/123]
// key๋Š” ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์ง€๋งŒ, ๋’ค๋กœ๊ฐ€๊ธฐํ•˜๋ฉด /๋กœ ์ด๋™

์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€

์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ด ํŒจํ„ด์„ ์ ์šฉํ•œ ๊ฒฐ๊ณผ

AS-IS

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋„ค์ด๋ฒ„๋ฅผ ๋ณด๋˜ ์ค‘, ๋™๋ฃŒ์—๊ฒŒ ๊ณต์œ ๋ฐ›์€ ๋งํฌ๋กœ ์ƒ์„ธ ํŽ˜์ด์ง€์— ๋‹ค์ด๋ ‰ํŠธ ์ ‘๊ทผ
  • ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ
  • ๋„ค์ด๋ฒ„๋กœ ๋Œ์•„๊ฐ (์„œ๋น„์Šค ์ดํƒˆ) ใ… ใ… 

TO-BE

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋„ค์ด๋ฒ„๋ฅผ ๋ณด๋˜ ์ค‘, ๋™๋ฃŒ์—๊ฒŒ ๊ณต์œ ๋ฐ›์€ ๋งํฌ๋กœ ์ƒ์„ธ ํŽ˜์ด์ง€์— ๋‹ค์ด๋ ‰ํŠธ ์ ‘๊ทผ
  • ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ
  • ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ (์„œ๋น„์Šค ์œ ์ง€) ๐Ÿ‘

๋งˆ์น˜๋ฉฐ

location.key๋Š” React Router๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ์ž˜ ์•Œ๋ ค์ง€์ง€ ์•Š์€ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ๊ณ ์œ  ์‹๋ณ„์ž ์—ญํ• ๋งŒ ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ป๊ฒŒ ํŽ˜์ด์ง€์— ๋„์ฐฉํ–ˆ๋Š”์ง€๋ฅผ ํŒ๋‹จํ•˜๋Š” ํ‚ค๊ฐ€ ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

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

์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—๋„ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์ด ์žˆ๋‹ค๋ฉด, ํ•œ๋ฒˆ ์ ์šฉํ•ด๋ณด์„ธ์š”. ์‚ฌ์šฉ์ž๋“ค์ด โ€œ์–ด? ์–ด๋””๋กœ ๊ฐ„ ๊ฑฐ์ง€?โ€ ํ•˜๋Š” ๋‹นํ™ฉ์Šค๋Ÿฌ์šด ๊ฒฝํ—˜์„ ํ•˜์ง€ ์•Š์„ ๊ฒ๋‹ˆ๋‹ค.


์ฐธ๊ณ  ์ž๋ฃŒ