隨著現代前端專案的複雜性日益增加,如何優雅地管理路由與資料查詢成為了開發者的重要課題。Vue Router 提供了優雅而強大的解決方案,讓我們可以更靈活地控制網站的導覽和資料呈現。
在本篇文章中,我們將會深入探討如何結合 Vue Router 和 GraphQL Variables,實作一個動態的文章詳細頁查詢。通過這個實戰演練,讀者不僅可以了解到這兩大技術的實際運用,更可以掌握它們如何協同工作,打造更為強大的 Web 應用。
Day14 開始前分支:feat/day_13/add_graphql-code-generator
Day14 進度完成分支:feat/day_14/implement_blog_detail_view_using_variables
Vue Router 是 Vue.js 官方的路由管理工具,專為單頁面應用(SPA)而設,讓開發者能夠建立動態路由匹配並實現無需刷新頁面的視圖切換。透過 <router-view>
和 <router-link>
兩個核心組件,它緊密整合 Vue.js,提供直觀的路由配置與導航功能,極大增強了前端應用的互動性和使用體驗。
先前,我們已經使用 Vue Router 設置了文章詳細頁的路由如下:src/router/index.ts
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
// ...
{
path: '/:id(\\d+)',
name: 'blog-detail',
component: () => import('@/views/BlogDetailView.vue'),
},
// ...
],
})
我們定義了一個路由參數 id
,且只匹配數字。所有符合這條路由規則的請求將會交由 BlogDetailView.vue
負責渲染,這便是動態路由匹配的應用。
在 BlogDetailView.vue
中,我們可以利用路徑參數(Path Parameter)來獲取所需的文章 id。
<script setup lang="ts">
// ...
import { useRoute } from 'vue-router'
const route = useRoute()
const variables = reactive({
postId: route.params.id as string,
})
// ...
</script>
既然我們已知道文章的 id,那麼如何使用 GraphQL Variables 來執行動態查詢呢?
首先,我們從撰寫 GraphQL 查詢開始。
首先,我們照先前學習到的,撰寫一個參數化的靜態的 GraphQL 查詢,這個查詢可以取得 id=1
的文章
query getPost {
post(id: 1) {
id
title
body
user {
id
name
email
}
comments {
data {
id
name
email
body
}
}
}
}
在 GraphQLZero Play Ground 測試查詢,可以成功執行取得資料:
當路由參數 id 改變時,我們希望查詢中的 id 也能同步更新,以確保獲得對應的文章資料。因此,我們需要利用 GraphQL Variables。
透過設定 GraphQL 查詢中的變數,我們可以動態地指定想要查詢的 id,並確保每次路由變更時,都能夠獲得正確的資料回應。
別忘了前一篇提到的,將 GraphQL 查詢抽出統一管理,有助於模組化且易於維護。
在 src/graphql/queries/index.ts
新增取得單篇文章的 GraphQL 查詢:
export const gqlGetPost = graphql(`
// 我們定義了一個 $postId 變數,並使用 `ID!` 型別表示這是一個非空的 ID
query getPost($postId: ID!) {
post(id: $postId) {
id
title
body
user {
id
name
email
}
comments {
data {
id
name
email
body
}
}
}
}
`)
src/views/BlogDetailView.vue
<script setup lang="ts">
import { computed, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useQuery } from '@vue/apollo-composable'
import { gqlGetPost } from '@/graphql/queries'
import NotFound from '@/components/layouts/NotFound.vue'
import ArticleDetail from '@/components/articles/ArticleDetail.vue'
// 取得路由參數
const route = useRoute()
// 使用 reactive
const variables = reactive({
postId: route.params.id as string,
})
// 監聽路由參數的變動,在每次變動時都要更新 variables.postId 的值
watch(
() => route.params.id,
(newId) => {
variables.postId = newId as string
},
)
// 使用 useQuery 獲取單篇文章資料
const { result, loading, error } = useQuery(gqlGetPost, variables)
const post = computed(() => (result.value?.post))
</script>
<template>
// ...
</template>
注意,我們使用了 reactive
,這是一個重要概念
什麼是 reactive
在 Vue Composition API 中,reactive 是用來創建一個響應式物件的。當該物件的屬性值改變時,所有使用到這些屬性的地方都會重新渲染或重新計算。
為什麼要使用 reactive
在 Vue 裡,我們希望該變數能夠自動更新並重新觸發 GraphQL 查詢。為了達到這個效果,我們把 variables 定義成響應式物件,這樣當 variables 內的值變動時,關聯的查詢就會重新運行。
換句話說,若在 useQuery
中,第二個參數我們僅傳遞 {postId: route.params.id}
,由於它不具備響應性,當 route.params.id
改變,Apollo Client 不會認為查詢需要刷新,因此也不會觸發新的 GraphQL 查詢。
reactive
並不是唯一的解法,這與 JavaScript 的「參考傳遞 (call by reference)」觀念有關。更多範例請參考官方文件 Variables of Queries | Vue Apollo
成功取得單篇文章資料後,就文章列表頁差不多的步驟。首先,剖析需要的功能元件:
Post
, User
, Comments
。我們將從 GraphQL API 獲取這個資料。完整程式碼範例請參考:feat/day_14/implement_blog_detail_view_using_variables
今天我們探討了如何結合 Vue Router 和 GraphQL Variables 實現動態文章詳細頁的查詢。透過 Vue 的 reactive 功能,確保了路由變更與資料查詢能夠即時同步,提供了更高的互動性和即時反應,使我們的 Web 應用體驗更佳。
明日,我們將採用分頁查詢的方式優化文章列表頁面。目前的設計會一次性呼叫全部文章 (100 篇),導致等待 API 回應時的使用者體驗不佳。不過沒關係,憑藉敏捷的精神,我們會不斷迭代和優化,直至創造出最佳的用戶體驗。