# ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ

๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ(Navigation Guard (opens new window))๋Š” ํŠน์ • URL์— ์ ‘๊ทผ(Navigation) ํ•˜๊ธฐ ์ „์— ๋ถˆ๋ ค์ง€๋Š” ํ›…(Hook)์˜ ์ผ์ข…์œผ๋กœ, ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์šฐํšŒ ํ•˜๊ฑฐ๋‚˜ ์ ‘๊ทผ ์ž์ฒด๋ฅผ ์ทจ์†Œ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๋ผ๊ณ  ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์— ๋”ฐ๋ผ ํŽ˜์ด์ง€ ์ ‘๊ทผ์„ ๋ง‰๊ฑฐ๋‚˜ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋”ฉํ•˜๊ธฐ ์ „์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค์ƒ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ๊ฑฐ์˜ ํ•„์ˆ˜๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

# ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ ์ข…๋ฅ˜

๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ์˜ ์ข…๋ฅ˜๋Š” ์ ์šฉ๋˜๋Š” ์œ„์น˜, ๋ฒ”์œ„์— ๋”ฐ๋ผ์„œ ์ „์—ญ, ์ง€์—ญ, ์ปดํฌ๋„ŒํŠธ 3๊ฐ€์ง€๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

# ์ „์—ญ ๊ฐ€๋“œ

์ „์—ญ ๊ฐ€๋“œ๋Š” ๋ชจ๋“  ๋ผ์šฐํŒ…์— ์ ์šฉ๋˜๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ์ž…๋‹ˆ๋‹ค. ๋ผ์šฐํ„ฐ์˜ beforeEach๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ „์—ญ๊ฐ€๋“œ์˜ ๋กœ์ง์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ „์—ญ ๊ฐ€๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

var router = new VueRouter();

router.beforeEach(function(to, from, next) {
  // ...
});

๋ทฐ ๋ผ์šฐํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ณ€์ˆ˜์— beforeEach() API๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ธ์ž๋กœ ๋ฐ›์€ 3๊ฐœ์˜ ๋ณ€์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

  • to : ์ด๋™ํ•  url
  • from : ํ˜„์žฌ url
  • next : to์—์„œ ์ง€์ •ํ•œ url๋กœ ์ด๋™ํ•˜๊ธฐ ์œ„ํ•ด ๊ผญ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ํ•จ์ˆ˜

TIP

next ํ•จ์ˆ˜์˜ ์ธ์ž์— ๋”ฐ๋ผ์„œ ๋ผ์šฐํŒ… ํ—ˆ์šฉ ์—ฌ๋ถ€๊ฐ€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.
next(): ๋ผ์šฐํŒ… ์Šน์ธ
next(false): ๋ผ์šฐํŒ… ์ทจ์†Œ
next('/'): ํŠน์ • ๋ผ์šฐํŠธ๋กœ ์ง„์ž… (route.push์ฒ˜๋Ÿผ ์ง„์ž…ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ๋กœ ์ง€์ • ๊ฐ€๋Šฅ. ์ฐธ์กฐ (opens new window))

WARNING

๋ผ์šฐํŒ… ํ—ˆ์šฉ ์—ฌ๋ถ€์— ์ƒ๊ด€์—†์ด ๋ฐ˜๋“œ์‹œ next๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋ผ์šฐํŒ…์ด ์ง„ํ–‰๋˜์ง€ ์•Š๊ณ  ๋Œ€๊ธฐ ์ƒํƒœ์— ๋น ์ง‘๋‹ˆ๋‹ค.

# ์ง€์—ญ ๊ฐ€๋“œ

์ง€์—ญ ๊ฐ€๋“œ๋Š” ๋ผ์šฐํŒ…๋ณ„๋กœ ์ ์šฉ๋˜๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ํŠน์ • ๋ผ์šฐํŠธ์˜ beforeEnter ์†์„ฑ์— ํ˜ธ์ถœํ•  ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

var router = new VueRouter({
  routes: [
    {
      path: "/login",
      component: Login,
      beforeEnter: function(to, from, next) {
        // ์ธ์ฆ ๊ฐ’ ๊ฒ€์ฆ ๋กœ์ง ์ถ”๊ฐ€
      },
    },
  ],
});

beforeEnter()์˜ ์ธ์ž 3๊ฐœ๋Š” ์•ž์—์„œ ์‚ดํŽด๋ณธ ๋‚ด์šฉ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

# ์ปดํฌ๋„ŒํŠธ ๊ฐ€๋“œ

์ปดํฌ๋„ŒํŠธ ๊ฐ€๋“œ๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ…์„ ์ œ์–ดํ•˜๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ์ž…๋‹ˆ๋‹ค. ๋ชฉ์ ์— ๋”ฐ๋ผ ๋‹ค์‹œ ์„ธ ์ข…๋ฅ˜๋กœ ๋‚˜๋‰˜์ง€๋งŒ ์ธ์ž๋“ค์€ ์•ž์—์„œ ์‚ดํŽด๋ณธ ์ „์—ญ, ์ง€์—ญ ๊ฐ€๋“œ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

# beforeRouteEnter

beforeRouteEnter๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์ „์ด๊ธฐ ๋•Œ๋ฌธ์— this๋ฅผ ํ†ตํ•œ ์ธ์Šคํ„ด์Šค ์ ‘๊ทผ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ์ธ์Šคํ„ด์Šค๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ์ฝœ๋ฐฑ์„ next์— ์ „๋‹ฌํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ ์ดํ›„์— ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

<script>
export default {
  data() {
    return {
      state: "pending",
    };
  },
  beforeRouteEnter(to, from, next) {
    // ๋„ค๋น„๊ฒŒ์ด์…˜ ์Šน์ธ ํ›„ state๋ฅผ ์—…๋ฐ์ดํŠธ
    next((vm) => (vm.state = "approved"));
  },
};
</script>

# beforeRouteUpdate

beforeRouteUpdate๋Š” ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ํŽ˜์ด์ง€ ์ฃผ์†Œ๊ฐ€ ๋ฐ”๋€” ๊ฒฝ์šฐ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋™์  ๋ผ์šฐํŒ…์„ ํ†ตํ•ด์„œ ํŽ˜์ด์ง€์˜ ์ฃผ์†Œ๋งŒ ๋ฐ”๋€Œ๊ณ  ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์˜ˆ๋กœ ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

new VueRouter({
  routes: [{ path: "/foo/:id", component: Foo }],
});
// ํ˜„์žฌ URL: /foo/1
<script>
export default {
  beforeRouteUpdate(to, from, next) {
    console.log(this.$route.params.id); // 1
    next();
  },
  methods: {
    moveToNext() {
      // ํŽ˜์ด์ง€๋ฅผ ์ด๋™ ํ•˜๊ธฐ์ „์— beforeRouteUpdate๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
      this.$router.push('/foo/2');
    },
  },
};
</script>

# beforeRouteLeave

beforeRouteLeave๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฒ—์–ด๋‚˜ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋ณดํ†ต ์‚ฌ์šฉ์ž๊ฐ€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ๊ฐ‘์ž‘์Šค๋Ÿฝ๊ฒŒ ์‚ฌ์ดํŠธ๋ฅผ ๋ฒ—์–ด๋‚  ๊ฒฝ์šฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. next(false)๋กœ ํŽ˜์ด์ง€ ์ด๋™์„ ๋ง‰์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('์‚ฌ์ดํŠธ์—์„œ ๋‚˜๊ฐ€์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ €์žฅ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

# ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ ํ˜ธ์ถœ ์ˆœ์„œ(flow)

  1. ๋น„ํ™œ์„ฑํ™”๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ beforeRouteLeave ํ˜ธ์ถœ
  2. ์ „์—ญ ๊ฐ€๋“œ beforeEach ํ˜ธ์ถœ
  3. ์žฌ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด beforeRouteUpdate ํ˜ธ์ถœ
  4. ์ง€์—ญ ๊ฐ€๋“œ beforeEnter ํ˜ธ์ถœ
  5. ํ™œ์„ฑํ™”๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ beforeRouteEnter ํ˜ธ์ถœ
  6. beforeRouteEnter์˜ next์— ๋„˜๊ฒจ์ค€ ์ฝœ๋ฐฑ ํ˜ธ์ถœ

# ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๋กœ ์ธ์ฆ ์ •๋ณด ํ™•์ธ

๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๊ฐ€ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ๊ณณ์€ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด์— ๋”ฐ๋ผ ์ ‘๊ทผ์„ ๋ง‰๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.

router.beforeEach(function(to, from, next) {
  // to: ์ด๋™ํ•  url์— ํ•ด๋‹นํ•˜๋Š” ๋ผ์šฐํŒ… ๊ฐ์ฒด
  if (
    to.matched.some(function(routeInfo) {
      return routeInfo.meta.authRequired;
    })
  ) {
    // ์ด๋™ํ•  ํŽ˜์ด์ง€์— ์ธ์ฆ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋ฉด ๊ฒฝ๊ณ  ์ฐฝ์„ ๋„์šฐ๊ณ  ํŽ˜์ด์ง€ ์ „ํ™˜์€ ํ•˜์ง€ ์•Š์Œ
    alert("Login Please!");
  } else {
    console.log("routing success : '" + to.path + "'");
    next(); // ํŽ˜์ด์ง€ ์ „ํ™˜
  }
});

# ์ฐธ๊ณ  ์ž๋ฃŒ