[Vue] Router

young-gue Park·2023년 11월 6일
0

Vue.js

목록 보기
7/10
post-thumbnail

⚡ Router


📌 Routing

🔷 네트워크에서 경로를 선택하는 프로세스

  • 웹 어플리케이션에서 다른 페이지 간의 전환과 경로를 관리하는 기술

🔷 SSR 에서의 Routing

  • 서버가 사용자가 방문한 URL 경로를 기반으로 응답을 전송
  • 링크를 클릭하면 브라우저는 서버로부터 HTML 응답을 수신하고 새 HTML로 전체 페이지를 다시 로드

🔷 CSR / SPA 에서의 Routing

  • SPA 에서 routing은 브라우저의 클라이언트 측에서 수행
  • 클라이언트 측 JavaScript가 새 데이터를 동적으로 가져와 전체 페이지를 다시 로드 하지 않음
  • 페이지는 1개이지만, 링크에 따라 여러 컴포넌트를 렌더링하여 마치 여러 페이지를
    사용하는 것처럼 보이도록 해야 함

🤔 만약 Routing 이 없다면?

  1. 유저가 URL을 통한 페이지의 변화를 감지할 수 없음
  2. 페이지가 무엇을 렌더링 중인지에 대한 상태를 알 수 없음
    • URL이 1개이기 때문에 새로 고침 시 처음 페이지로 되돌아감
    • 링크를 공유할 시 첫 페이지만 공유 가능
  3. 브라우저의 뒤로 가기 기능을 사용할 수 없음

📌 Vue Router

💡 Vite 로 프로젝트 생성 시 Router 추가를 Yes로 설정한다.

서버 실행 후

🔷 Vue 프로젝트 구조 변화

1. App.vue 코드 변화

<template>
  <div>
    <h1>AppVue</h1>
    <header>
      <RouterLink to="/">Home</RouterLink>
      <RouterLink :to="{name: 'home'}">HomeName</RouterLink>
      <RouterLink to="/about">about</RouterLink>
      <RouterLink :to="{name: 'about'}">aboutName</RouterLink>
    </header>    
    <RouterView />
  </div>
</template>

<script setup>
import { RouterView } from 'vue-router'

</script>

<style scoped>
  header {
    display: flex;
    justify-content: space-around;
  }

  a {
    text-decoration: none;
  }
</style>

🔷 RouterLink

  • 페이지를 다시 로드 하지 않고 URL을 변경하고 URL 생성 및 관련 로직을 처리
  • HTML의 a 태그를 렌더링한 것

🔷 RouterView

  • URL에 해당하는 컴포넌트를 표시
  • 어디에나 배치하여 레이아웃에 맞출 수 있음

2. router 폴더 생성

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
import UserView from '../views/UserView.vue'

//위에서 import한 생성 인자를 옵션으로 던지기
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  //URI: 경로/컴포넌트(views) 매핑
  routes: [
    {
      path: '/',
      name: 'home', //컴포넌트의 이름을 지정해 편하게 가져오기 위한 용도, 필수 아님
      component: HomeView
    },
    {
      path: '/about',
      name: 'about',
      component: AboutView
    },
    {
      path: '/user/:id', //동적 라우팅 
      name: 'user',
      component: UserView
    },
  ]
})

export default router

🔷 router/index.js

  • 라우팅에 관련된 정보 및 설정이 작성 되는 곳
  • router에 URL과 컴포넌트를 매핑

🔷 라우팅 기본

  • index.js 에 라우터 관련 설정 작성 (주소, 이름, 컴포넌트)
  • RouterLink의 ‘to’ 속성으로 index.js 에서 정의한 주소 속성 값 (path)을 사용

🔷 Named Routes

  • 경로에 이름을 지정하는 라우팅
  • name 속성 값에 경로에 대한 이름을 지정
  • 경로에 연결하려면 RouterLink에 v-bind를 사용해 ‘to’ prop 객체로 전달가능
  • 하드 코딩 된 URL을 사용하지 않아도 됨
  • URL 입력 시 오타 방지
<RouterLink :to="{name: 'home'}">HomeName</RouterLink>

3. views 폴더 생성

🔷 views

  • RouterView 위치에 렌더링 할 컴포넌트를 배치
  • 기존 components 폴더와 기능적으로 다른 것은 없으며 단순 분류의 의미로 구성됨\

❗ 일반 컴포넌트와 구분하기 위해 컴포넌트 이름을 View로 끝나도록 작성하는 것을 권장한다.

⭐ 매개 변수를 사용한 동적 경로 매칭

  • 주어진 패턴 경로를 동일한 컴포넌트에 매핑 해야 하는 경우 활용

ex) 모든 사용자의 ID를 활용하여 프로필 페이지 URL을 설계한다면?

  • user/1 user/2 user/3 처럼 일정한 패턴의 URL 작성을 반복해야 한다.

1. UserView 컴포넌트 라우트 등록

  • 매개변수는 콜론 (:) 으로 표기
// index.js
import UserView from '../views/UserView.vue'

const router = createRouter({
  routes: [
    {
      path: '/user/:id',
      name: 'user',
      component: UserView
    },
  ]
})

2. 라우트의 매개변수는 컴포넌트에서 $route.params로 참조 가능

<!-- 아래와 같이 접근 가능하지만 권장 하지 않는다! -->
<p>{{$route.params.id}}</p>

3. 하지만 라우트의 매개변수는 다음과 같이 Composition API 방식으로 작성 하는 것을 권장

<template>
    <div>
        <h2>UserView</h2>
        <!-- 아래와 같이 접근 가능하지만 권장 하지 않는다! -->
        <p>{{$route.params.id}}</p>
        <!-- 아래와 같은 작성을 권장 -->
        <p>{{userId}}</p>
    </div>
</template>

<script setup>
import { useRoute } from 'vue-router';
import { ref } from 'vue';

const route = useRoute();

const userId = ref(route.params.id);

</script>

<style scoped>

</style>

💡 userId 변경 시에 변경된 value가 바로 적용되게 하기 위해서 watch()를 사용한다.

watch(() => route.params.id, (newId) => {
    userId2.value = newId;
});
<!-- 아래와 같이 접근 가능하지만 권장 하지 않는다! -->
<p>{{$route.params.id}}</p>
<!-- 아래와 같은 작성을 권장 -->
<p>{{userId}}</p>
<!-- value 즉시 변경 적용 -->
<p>{{userId2}}</p>

bzeromo 에서 gue로 이동 시 userId2는 바로 변경이 적용되었다.
이 방법 외에도 onBeforeRouteUpdate()를 이용하는 방법이 있는데 이는 잠시후에 알아본다.

⭐ 프로그래밍 방식 네비게이션

🔷 router 의 인스턴스 메서드를 사용해 RouterLink로 a 태그를 만드는 것처럼 프로그래밍으로 네비게이션 관련 작업을 수행할 수 있음

1. 다른 위치로 이동 하기 → router.push()

  • 다른 URL로 이동하는 메서드
  • 새 항목을 history stack에 push 하므로 사용자가 브라우저 뒤로 가기 버튼을 클릭하면 이전 URL 이동 가능
  • RouterLink를 클릭했을 때 내부적으로 호출되는 메서드 이므로 RouterLink를 클릭하는 것은
    router.push()를 호출하는 것과 같음
//컴포넌트 이동
const router = useRouter();

const goHome = function() {
    //router.push('/');
    router.push({name: 'home'})
  
  	// literal string path
    //router.push('/users/alice')
    // object with path
    //router.push({ path: '/users/alice' })
    // named route with params to let the router build the url
    //router.push({ name: 'user', params: { username: 'alice' } })
    // with query, resulting in /register?plan=private
    //router.push({ path: '/register', query: { plan: 'private' } })
}
<button @click="goHome">홈으로</button>

2. 현재 위치 바꾸기 → router.replace()

  • push 메서드와 달리 history stack 에 새로운 항목을 push 하지 않고 다른 URL 로 이동
    (= 이동 전 URL로 뒤로 가기 불가)
const router = useRouter();

const goHome = function() {
    router.replace({name: 'home'})
}

📌 Navigation Guard

🔷 Vue router 를 통해 특정 URL에 접근할 때 다른 URL로 redirect를 하거나 취소하여 네비게이션을 보호

ex) 로그인이 되어있는데 굳이 링크에 /login을 추가해 어떻게든 다시 로그인 페이지로 넘어가려는 악의 추종자들이 있다... 🤦‍♂️

🔷 Navigation Guard 종류

  • Globally (전역 가드)
    • 어플리케이션 전역에서 동작
    • index.js 에서 정의
  • Per-route (라우터 가드)
    • 특정 route 에서만 동작
    • index.js 의 각 routes에 정의
  • In-component (컴포넌트 가드)
    • 특정 컴포넌트 내에서만 동작
    • 컴포넌트 script 에 정의

⭐ Globally Guard

🔷 router.beforeEach()

  • 다른 URL로 이동하기 직전에 실행되는 함수 (Global Before Guards)
router.beforeEach((to, from) => {
  // console.log(to)
  // console.log(from)
  //전역 가드(Globally Guard)
  if (!isAuth && to.name != 'login') {
    console.log("로그인이 필요합니다.")
    return { name: "login" };
  }
})

로그인 전(isAuth가 false일 때)에는 다른 페이지로 이동할 수가 없다.

  • to : 이동 할 URL 정보가 담긴 Route 객체
  • from : 현재 URL 정보가 담긴 Route 객체
  • 선택적 반환 (return) 값
    1) false
    • 현재 네비게이션을 취소
    • 브라우저 URL 이 변경된 경우 (사용자가 수동으로 또는 뒤로 버튼을 통해) from 경로의 URL로 재설정
    2) Route Location
    • router.push() 를 호출하는 것처럼 경로 위치를 전달하여 다른 위치로 redirect

💡 return 이 없다면 ’to’ URL Route 객체로 이동한다.

⭐ Per-route Guard

🔷 router.beforeEnter()

  • route에 진입했을 때만 실행되는 함수
  • 매개변수, 쿼리 값이 변경될 때는 실행되지 않고 다른 경로에서 탐색할 때만 실행됨
{
  path: '/login',
  name: 'login',
  component: LoginView,
  //Per-route Guard
  beforeEnter: (to, from) => {
    if (isAuth) {
       console.log("이미 로그인 하셨습니다.");
       return { name: 'home' };
    }
  }
},

로그인 상태일 때 로그인 뷰로 넘어갈 수 없게끔 막혔다.

  • routes 객체에서 정의
  • 함수의 to, from, 선택 반환 인자는 beforeEach 와 동일

⭐ In-component Guard

🔷 onBeforeRouteLeave

  • 현재 라우트에서 다른 라우트로 이동하기 전에 실행
  • 사용자가 현재 페이지를 떠나는 동작에 대한 로직을 처리
onBeforeRouteLeave(() => {
    const answer = confirm("정말 나갈거임?");

    if (!answer) return false;
});

userView에서 다른 뷰로 이동 시에 자동으로 팝업이 뜨며, 확인을 누르면 이동한다.

💡 window.confirm()
팝업을 띄워 확인 시 true, 취소 시 false를 반환한다.

🔷 onBeforeRouteUpdate

  • 이미 렌더링된 컴포넌트가 같은 라우트 내에서 업데이트 되기 전에 실행
  • 라우트 업데이트 시 추가적인 로직을 처리
onBeforeRouteUpdate((to) => {
    userId.value = to.params.id;
})

이제 유저 정보가 갱신되면 모든 컴포넌트가 이를 즉각 반영한다.


Router 개념은 다시 봐도 복잡해~

profile
Hodie mihi, Cras tibi

0개의 댓글

관련 채용 정보