๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โญ Personal_Study/Vue

Navigation Guard

by ํฌ์ŠคํŠธ์‰์ดํฌ 2022. 11. 19.

Navigation Guard

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

โœ” Vue router๋ฅผ ํ†ตํ•ด ํŠน์ • URL์— ์ ‘๊ทผํ•  ๋•Œ ๋‹ค๋ฅธ url๋กœ redirect ํ•˜๊ฑฐ๋‚˜ ํ•ด๋‹น URL๋กœ์˜ ์ ‘๊ทผ์„ ๋ง‰๋Š” ๋ฐฉ๋ฒ•

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

โœ” ์ „์—ญ ๊ฐ€๋“œ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ์—์„œ ๋™์ž‘
โœ” ๋ผ์šฐํ„ฐ ๊ฐ€๋“œ: ํŠน์ • url์—์„œ๋งŒ ๋™์ž‘
โœ” ์ปดํฌ๋„ŒํŠธ ๊ฐ€๋“œ: ๋ผ์šฐํ„ฐ ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์ •์˜

์ „์—ญ ๊ฐ€๋“œ

Global Before Guard

โœ” ๋‹ค๋ฅธ url ์ฃผ์†Œ๋กœ ์ด๋™ํ•  ๋•Œ ํ•ญ์ƒ ์‹คํ–‰
โœ” router/index.js์— router.beforeEach()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •
โœ” ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ๊ฐ’์œผ๋กœ ๋‹ค์Œ 3๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค

  1. to: ์ด๋™ํ•  url ์ •๋ณด๊ฐ€ ๋‹ด๊ธด Route ๊ฐ์ฒด
  2. from: ํ˜„์žฌ url ์ •๋ณด๊ฐ€ ๋‹ด๊ธด route ๊ฐ์ฒด
  3. next: ์ง€์ •ํ•œ url๋กœ ์ด๋™ํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜
    • ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ๋ฐ˜๋“œ์‹œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ
    • ๊ธฐ๋ณธ์ ์œผ๋กœ to์— ํ•ด๋‹นํ•˜๋Š” url๋กœ ์ด๋™

โœ” URL์ด ๋ณ€๊ฒฝ๋˜์–ด ํ™”๋ฉด์ด ์ „ํ™˜๋˜๊ธฐ ์ „ router.beforeEach() ํ˜ธ์ถœ

  • ํ™”๋ฉด์ด ์ „ํ™˜๋˜์ง€ ์•Š๊ณ  ๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค

โœ” ๋ณ€๊ฒฝ๋œ URL๋กœ ๋ผ์šฐํŒ…๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” next() ํ˜ธ์ถœ ํ•„์š”

  • next() ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€ ํ™”๋ฉด์ด ์ „ํ™˜๋˜์ง€ ์•Š๋Š”๋‹ค.

Global Before Guard

// router/index.js

...

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

router.beforeEach((to, from, next) => {
  console.log('to', to)
  console.log('from', from)
  console.log('next', next)
})

โœ” /home/์œผ๋กœ ์ด๋™ํ•˜๋”๋ผ๋„ ๋ผ์šฐํŒ…์ด ๋˜์ง€ ์•Š๊ณ  ์œ„์™€ ๊ฐ™์ด ๋กœ๊ทธ๋งŒ ์ถœ๋ ฅ๋œ๋‹ค.
โœ” next()๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์œผ๋ฉด ํ™”๋ฉด์ด ์ „ํ™˜๋˜์ง€ ์•Š๋Š”๋‹ค.

// router/index.js

...

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

router.beforeEach((to, from, next) => {
  console.log('to', to)
  console.log('from', from)
  console.log('next', next)
  next()
})

export default router

โœ” to์—๋Š” ์ด๋™ํ•  url์ธ about์— ๋Œ€ํ•œ ์ •๋ณด
โœ” from์—๋Š” ํ˜„์žฌ url์ธ home์— ๋Œ€ํ•œ ์ •๋ณด

Login ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ

  1. Login์ด ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด Login ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€
// views/LoginView.vue


<template>
  <div>
    <h1>๋กœ๊ทธ์ธ ํŽ˜์ด์ง€</h1>
  </div>
</template>

<script>
export default {
  name: 'LoginView'
}
</script>

<style>

</style>
// router/index.js

import LoginView from '@/views/LoginView'

Vue.use(VueRouter)

const routes = [
  {
    path: '/login',
    name: 'login',
    component: LoginView
  }
]
  1. LoginView์— ๋Œ€ํ•œ ๋ผ์šฐํ„ฐ ๋งํฌ ์ถ”๊ฐ€
// App.vue

<template>
  <div id="app">
    <nav>
      ...
      <router-link :to="{ name: 'login' }">Login</router-link>
    </nav>
  1. Login ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ
// router/index.js

router.beforeEach((to, from, next) => {
  // ๋กœ๊ทธ์ธ ์—ฌ๋ถ€(์ž„์‹œ๋กœ)
  const isLoggedIn = true

  // ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ํŽ˜์ด์ง€
  const authPages = ['hello']

  // ์•„ํ”™๋กœ ์ด๋™ํ•  ํŽ˜์ด์ง€(to)๊ฐ€ ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ์‚ฌ์ดํŠธ์ธ์ง€ ํ™•์ธ
  const isAuthRequired = authPages.includes(to.name)

  if (isAuthRequired && !isLoggedIn) {
    next({ name: 'login' })
  } else {
    next()
  }
})

โœ” isAuthRequired ๊ฐ’์— ๋”ฐ๋ผ ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ํŽ˜์ด์ง€์ด๊ณ  ๋กœ๊ทธ์ธ์ด ์•ˆ๋˜์–ด ์žˆ์œผ๋ฉด Login ํŽ˜์ด์ง€๋กœ ์ด๋™

  1. view๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด
// router/index.js

router.beforeEach((to, from, next) => {
  // ๋กœ๊ทธ์ธ ์—ฌ๋ถ€(์ž„์‹œ๋กœ)
  const isLoggedIn = true

  const allowAllPages = ['login']

  // ์•„ํ”™๋กœ ์ด๋™ํ•  ํŽ˜์ด์ง€(to)๊ฐ€ ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ์‚ฌ์ดํŠธ์ธ์ง€ ํ™•์ธ
  const isAuthRequired = !allowAllPages.includes(to.name)

  if (isAuthRequired && !isLoggedIn) {
    next({ name: 'login' })
  } else {
    next()
  }
})

โœ” Login ํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ชจ์•„๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

๋ผ์šฐํ„ฐ ๊ฐ€๋“œ

๊ฐœ์š”

โœ” ์ „์ฒด route๊ฐ€ ์•„๋‹Œ ํŠน์ • route์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐ€๋“œ ์„ค์ •
โœ” beforEnter()

  • route์— ์ง„์ž…ํ–ˆ์„ ๋Œ€ ์‹คํ–‰
  • ๋ผ์šฐํ„ฐ๋ฅผ ๋“ฑ๋กํ•œ ์œ„์น˜์— ์ถ”๊ฐ€
  • ๋‹จ ๋งค๊ฐœ๋ณ€์ˆ˜, ์ฟผ๋ฆฌ, ํ•ด์‹œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ๊ฒฝ๋กœ์—์„œ ํƒ์ƒ‰ํ•  ๋•Œ๋งŒ ์‹คํ–‰
  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” to, from, next๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.

Login ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ

โœ” ์ด๋ฏธ ๋กœ๊ทธ์ธ ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์— HomeView๋กœ ์ด๋™ํ•˜๊ธฐ

// router/index.js

const isLoggedIn = true

const routes = [
  {
    path: '/login',
    name: 'login',
    component: LoginView,
    beforeEnter: (to, from, next) => {
      if (isLoggedIn === true) {
        console.log('์ด๋ฏธ ๋กœ๊ทธ์ธ')
        next({ name: 'home' })
      } else {
        next()
      }
    }
  }
]

โœ” ๋กœ๊ทธ์ธ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ์ž„์‹œ ๋ณ€์ˆ˜ ์ƒ์„ฑ
โœ” ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ home์œผ๋กœ ์ด๋™
โœ” ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ login์œผ๋กœ ์ด๋™

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

๊ฐœ์š”

โœ” ํŠน์ • ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๊ฐ€๋“œ๋ฅผ ์ง€์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ
โœ” beforeRouteUpdate(): ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ๋กœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ

Params ๋ณ€ํ™” ๊ฐ์ง€

โœ” navbar์— ์žˆ๋Š” Hello๋ฅผ ๋ˆ„๋ฅด๋ฉด sunjun์—๊ฒŒ ์ธ์‚ฌํ•˜๋Š” ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋ฉด URL์€ ๋ณ€ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€๋Š” ๋ณ€ํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค.
โœ” ๋ณ€ํ™”ํ•˜์ง€ ์•Š๋Š” ์ด์œ 

  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ์‚ฌ์šฉ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— lifecycle hook์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , ๋”ฐ๋ผ์„œ $route.params์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๋‹ค.
<script>
export default {
  name: 'HelloView',
  data() {
    return {
      userName: this.$route.params.userName
    }
  },
  beforeRouteUpdate(to, from, next) {
    this.userName = to.params.userName
    next()
  }
}
</script>

โœ” userName์„ ์ด๋™ํ•  params์— ์žˆ๋Š” userName์œผ๋กœ ์žฌํ• ๋‹น

404 Not Found

404 Not Found

// views/NotFound404

<template>
  <div>
    <h1>404 Not Found</h1>
  </div>
</template>

<script>
export default {
  name: 'NotFound404'
}
</script>
// router/index.js

import NotFound404 from '@/views/NotFound404'

Vue.use(VueRouter)

const routes = [
  ...
  {
    path: '/404',
    name: 'NotFound404',
    component: NotFound404
  },
]

์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

// router/index.js

const routes = [
  ...
  {
    path: '*',
    redirect: '/404
  },
]

โœ” ๋ชจ๋“  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด 404page๋กœ redirect ์‹œํ‚ค๊ธฐ

  • ๊ธฐ์กด์— ๋ช…์‹œํ•œ ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  ๊ฒฝ๋กœ๊ฐ€ 404page๋กœ redirect
  • routes ์ตœํ•˜๋‹จ๋ถ€์— ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค

ํ˜•์‹์€ ์œ ํšจํ•˜์ง€๋งŒ ํŠน์ • ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ

โœ” ๊ฐ•์•„์ง€ ์‚ฌ์ง„ ์ถœ๋ ฅ ํŽ˜์ด์ง€

<template>
  <div>
    <img :src="imgSrc" alt="">
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'DogView',
  data() {
    return {
      imgSrc: null,
    }
  },
  methods: {
    getDogImage() {
      const breed = this.$route.params.breed
      const dogImageUrl = `https://dog.ceo/api/breed/${breed}/images/random`
      axios({
        method: 'get',
        url: dogImageUrl
      })
        .then((response) => {
          const imgSrc = response.data.message
          this.imgSrc = imgSrc
        })
        .catch((error) => {
          console.log(error)
        })
    }
  },
  created() {
    this.getDogImage()
  }
}
</script>

<style>

</style>
// views/DogView.vue

const routes = [
  ...
  {
    path: '/dog/:breed',
    name: 'dog',
    component: DogView
  },
]

โœ” Dog api axios ๋กœ์ง ์ž‘์„ฑ

// views/DogView.vue


<template>
  <div>
    <p v-if="!imgSrc">{{ message }}</p>
    <img :src="imgSrc" alt="">
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'DogView',
  data() {
    return {
      imgSrc: null,
      message: '๋กœ๋”ฉ์ค‘...'
    }
  },
  ...
}
// views/DogView.vue

axios({
        method: 'get',
        url: dogImageUrl
      })
        .then((response) => {
          const imgSrc = response.data.message
          this.imgSrc = imgSrc
        })
        .catch((error) => {
          this.message=`${this.$route.params.breed}๋Š” ์—†๋Š” ํ’ˆ์ข…์ž…๋‹ˆ๋‹ค.`
          console.log(error)
        })

โœ” ์š”์ฒญ ์‹คํŒจ์‹œ error์—์„œ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅํ•˜๊ธฐ

404 Not Found๋กœ ์ด๋™ ์‹œํ‚ค๊ธฐ

// views/DogView.vue

axios({
        method: 'get',
        url: dogImageUrl
      })
        .then((response) => {
          const imgSrc = response.data.message
          this.imgSrc = imgSrc
        })
        .catch((error) => {
          this.$router.push('/404')
          console.log(error)
        })

'โญ Personal_Study > Vue' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Vue with DRF: Server & Client  (0) 2022.11.20
Article with Vue  (0) 2022.11.19
Vue Router  (0) 2022.11.18
UX & UI  (0) 2022.11.18
Todo: Local Storage  (0) 2022.11.16

๋Œ“๊ธ€