본문 바로가기

Java Scripts/Vue.js

Vue : Nested Routes

728x90

Nested Routes 

Each URL provides different information on that resource:

각 URL은 해당 리소스에 대한 다양한 정보를 제공합니다.

  • /event/2 - Event Details (information)
  • /event/2/register - Event Register (to signup for the event)
  • /event/2/edit - Event Edit (to edit the event)

Problem: Where do we place these components?

Solution: In their own folder. (event folder)

/event/2 /src/views/event/Details.vue
/event/2/register /src/views/event/Register.vue
/event/2/edit /src/views/event/Edit.vue

 

 

Problem: How do we create and route to these views?

There will be some duplicate code in this solution, which I’ll show you how to solve using Vue Router’s Nested Routes.

이 솔루션에는 중복된 코드가 있을 수 있는데, Vue Router의 중첩 경로를 사용하여 해결하는 방법을 보여 드리겠습니다.

 

Solution: Basic Routing

import { createRouter, createWebHistory } from 'vue-router'
import About from '@/views/About.vue'
import EventList from '@/views/EventList.vue'
import EventDetails from '@/views/event/Details.vue'
import EventRegister from '@/views/event/Register.vue'
import EventEdit from '@/views/event/Edit.vue'

const routes = [
  {
    path: '/',
    name: 'EventList',
    component: EventList
    props: route => ({ page: parseInt(route.query.page) || 1 })
  },
  {
    path: '/event/:id',
    name: 'EventDetails',
    props: true,
    component: EventDetails
  },
  {
    path: '/event/:id/register',
    name: 'EventRegister',
    props: true,
    component: EventRegister
  },
  {
    path: '/event/:id/edit',
    name: 'EventEdit',
    props: true,
    component: EventEdit
  },
  ...

Notice how I’m importing the components, using a dynamic route, and specifying props: true to send the id part of the URL as a prop into the components. 

dynamic route를 사용하여 components,를 가져오고, URL의 ID 부분을 components에 prop 으로 보내기 위해 props: true를 지정하는 방법에 주목하세요.

 

 /src/views/event/Details.vue

<template>
  <div v-if="event">
    <h1>{{ event.title }}</h1>
    <div id="nav">
      <router-link :to="{ name: 'EventDetails', params: { id } }"
        >Details</router-link
      >
      |
      <router-link :to="{ name: 'EventRegister', params: { id } }"
        >Register</router-link
      >
      |
      <router-link :to="{ name: 'EventEdit', params: { id } }"
        >Edit</router-link
      >
    </div>
    <p>{{ event.time }} on {{ event.date }} @ {{ event.location }}</p>
    <p>{{ event.description }}</p>
  </div>
</template>

<script>
import EventService from '@/services/EventService.js'
export default {
  props: ['id'],
  data() {
    return {
      event: null
    }
  },
  created() {
    EventService.getEvent(this.id)
      .then(response => {
        this.event = response.data
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

Notice in here I display the event title, and then link to all of the event components.

여기에 이벤트 제목을 표시한 다음 모든 이벤트 구성 요소에 대한 링크를 표시합니다. 

/src/views/event/Register.vue

<template>
  <div v-if="event">
    <h1>{{ event.title }}</h1>
    <div id="nav">
      <router-link :to="{ name: 'EventDetails', params: { id } }"
        >Details</router-link
      >
      |
      <router-link :to="{ name: 'EventRegister', params: { id } }"
        >Register</router-link
      >
      |
      <router-link :to="{ name: 'EventEdit', params: { id } }"
        >Edit</router-link
      >
    </div>
    <p>Regstration form here</p>
  </div>
</template>

<script>
import EventService from '@/services/EventService.js'
export default {
  props: ['id'],
  data() {
    return {
      event: null
    }
  },
  created() {
    EventService.getEvent(this.id)
      .then(response => {
        this.event = response.data
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

Problem: We’re repeating the header and navigation on each page.

You might notice that there’s some repetition going on. Specifically the header and the navigation. 

특히 헤더와 navigation 에서 반복이 진행되고 있음을 알 수 있습니다. 

Wouldn’t it be nice if we could eliminate that duplication? We also have the same API calling code in each component. 

그 중복을 없앨 수 있다면 좋지 않을까요? 또한 각 구성 요소에는 동일한 API 호출 코드가 있습니다.

 

Solution: Nested Routes

we already have a top level <router-view> but we’ve stumbled upon an instance where we need another <router-view> or custom layout for all the event profile components.

이미 최상위 수준 <router-view>가 있지만 모든 이벤트 프로필 components에 대해 또 다른 <router-view> 또는 사용자 정의 레이아웃이 필요한 인스턴스를 우연히 발견했습니다.

 

/src/views/event/Layout.vue

<template>
  <div v-if="event">
    <h1>{{ event.title }}</h1>
    <div id="nav">
      <router-link :to="{ name: 'EventDetails', params: { id } }"
        >Details</router-link
      >
      |
      <router-link :to="{ name: 'EventRegister', params: { id } }"
        >Register</router-link
      >
      |
      <router-link :to="{ name: 'EventEdit', params: { id } }"
        >Edit</router-link
      >
    </div>
    <router-view :event="event" />
  </div>
</template>
<script>
import EventService from '@/services/EventService.js'
export default {
  props: ['id'],
  data() {
    return {
      event: null
    }
  },
  created() {
    EventService.getEvent(this.id)
      .then(response => {
        this.event = response.data
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

Notice

  • This layout has the duplicate code from the 3 components we listed.
  • 이 레이아웃에는 우리가 나열한 3개 구성 요소의 중복 코드가 있습니다.
  • <router-view :event="event" /> is passing down the event object from our API.
  • <router-view :event="event" />는 API에서 이벤트 객체를 전달합니다.
  • Those components are quite simple like below.
  • 해당 구성 요소는 아래와 같이 매우 간단합니다.

note) <router-view :event="event" /> 을 통하여 아래 Detail.vue,  Register.vue, Edit.Vue 로 evant object 가 넘어간다.

 

/src/views/event/Details.vue

<template>
  <p>{{ event.time }} on {{ event.date }} @ {{ event.location }}</p>
  <p>{{ event.description }}</p>
</template>
<script>
export default {
  props: ['event']
}
</script>

 

 

/src/views/event/Register.vue

<template>
  <p>Register for the event here</p>
</template>
<script>
export default {
  props: ['event']
}
</script>

 

 

/src/views/event/Edit.vue

<template>
  <p>Edit the event here</p>
</template>
<script>
export default {
  props: ['event']
}
</script>

 

 

/src/router/index.js

Mapping these Nested Routes together in our router file.

import { createRouter, createWebHistory } from 'vue-router'
import EventList from '../views/EventList.vue'
import EventLayout from '../views/event/Layout.vue'
import EventDetails from '../views/event/Details.vue'
import EventRegister from '../views/event/Register.vue'
import EventEdit from '../views/event/Edit.vue'
import About from '../views/About.vue'

const routes = [
  {
    path: '/',
    name: 'EventList',
    component: EventList,
    props: route => ({ page: parseInt(route.query.page) || 1 })
  },
  {
    path: '/event/:id',
    name: 'EventLayout',
    props: true,
    component: EventLayout,
    children: [  // <-----
      {
        path: '',
        name: 'EventDetails',
        component: EventDetails
      },
      {
        path: 'register',
        name: 'EventRegister',
        component: EventRegister
      },
      {
        path: 'edit',
        name: 'EventEdit',
        component: EventEdit
      }
    ]
  },
  ...

Notice

  • The first is to notice our EventLayout route with the children option, which is sending in an another array of routes
  • 첫 번째는 다른 경로 배열을 보내는, children 옵션이 있는 EventLayout 경로가 있는 것입니다.
  • How the children are inheriting the path /event/:id from the parent route.
  • 하위 항목이 상위 경로의 /event/:id 경로를 어떻게 상속하냐 하는 것이다.
  • EventDetails has a blank path, this is what gets loaded into <router-view /> when /event/:id is visited.
  • EventDetails에는 빈 경로가 있습니다. 이는 /event/:id를 방문할 때 <router-view />에 로드되는 경로입니다.
  • /user/:id/register and /user/:id/edit simply load up the proper routes.
  • /user/:id/register 및 /user/:id/edit는 단순히 적절한 경로를 로드합니다.

 

One more optimization

 

/src/views/event/Layout.vue (before optimization)

<template>
  <div v-if="event">
    <h1>{{ event.title }}</h1>
    <div id="nav">
      <router-link :to="{ name: 'EventDetails', params: { id } }"
        >Details</router-link
      >
      |
      <router-link :to="{ name: 'EventRegister', params: { id } }"
        >Register</router-link
      >
      |
      <router-link :to="{ name: 'EventEdit', params: { id } }"
        >Edit</router-link
      >
    </div>

 

 

 /src/views/event/Layout.vue (after optimization)

note) optimized code 에서는 params: { id }  없어져 있다

<template>
  <div v-if="event">
    <h1>{{ event.title }}</h1>
    <div id="nav">
      <router-link :to="{ name: 'EventDetails }"
        >Details</router-link
      >
      |
      <router-link :to="{ name: 'EventRegister' }"
        >Register</router-link
      >
      |
      <router-link :to="{ name: 'EventEdit' }"
        >Edit</router-link
      >
    </div>
    ...

Since these links all require :id , when the router-link is rendered in the template (if it’s not sent in) it will look at the URL parameters, and if :id exists in the current route, it will use the :id in all of the link URLs.

이러한 링크에는 모두 :id가 필요하므로 router-link가 템플릿에서 렌더링된 경우(전송되지 않은 경우) URL 매개변수를 확인하고,  :id가 현재 경로에 존재하는 경우 모든 링크 URL에서 :id를 사용한다. 

 

 

 

Sample Codes

https://github.com/Code-Pop/Touring-Vue-Router/tree/L4-end

 

GitHub - Code-Pop/Touring-Vue-Router

Contribute to Code-Pop/Touring-Vue-Router development by creating an account on GitHub.

github.com

 

'Java Scripts > Vue.js' 카테고리의 다른 글

Vue : Global Component  (0) 2022.01.08
Vue : Single File Component  (0) 2022.01.08
Vue : Dynamic Routing & History Mode  (0) 2022.01.08
Vue Router Basics  (0) 2021.12.31
Vue : Slots: Fundamentals  (0) 2021.12.31