iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
Vue.js

Vue & GraphQL 探險之旅:30天,從新手村到魔王之巔系列 第 14

[Day14] 實戰演練:用 Vue Router & GraphQL Variables 實作文章詳細頁動態查詢

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231015/20141111VdxFs7ZHam.png

隨著現代前端專案的複雜性日益增加,如何優雅地管理路由與資料查詢成為了開發者的重要課題。Vue Router 提供了優雅而強大的解決方案,讓我們可以更靈活地控制網站的導覽和資料呈現。

在本篇文章中,我們將會深入探討如何結合 Vue RouterGraphQL Variables,實作一個動態的文章詳細頁查詢。通過這個實戰演練,讀者不僅可以了解到這兩大技術的實際運用,更可以掌握它們如何協同工作,打造更為強大的 Web 應用。


文章範例程式碼 GitHub

範例程式碼 GitHub 連結

Day14 開始前分支:feat/day_13/add_graphql-code-generator
Day14 進度完成分支:feat/day_14/implement_blog_detail_view_using_variables


Vue Router

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 負責渲染,這便是動態路由匹配的應用。

透過 Vue Router 取得特定文章 id

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>

使用 GraphQL Variables 進行動態查詢

既然我們已知道文章的 id,那麼如何使用 GraphQL Variables 來執行動態查詢呢?

首先,我們從撰寫 GraphQL 查詢開始。

靜態的 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 測試查詢,可以成功執行取得資料:
https://ithelp.ithome.com.tw/upload/images/20231015/20141111iJUb6yWft0.png

使用 GraphQL Variables

當路由參數 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
                }
            }
        }
    }
`)

在 Vue Component 使用查詢

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

開發文章詳細頁 Vue 元件

成功取得單篇文章資料後,就文章列表頁差不多的步驟。首先,剖析需要的功能元件:

  1. 單篇文章資料:一個包含一篇文章的物件,有 Post, User, Comments。我們將從 GraphQL API 獲取這個資料。
  2. 文章詳細頁容器:展示該篇文章的所有屬性項目,包括但不限於標題、內容、作者、評論等。
  3. 文章評論容器:展示該文章所有評論。
  4. 文章評論項目卡片:展示單一評論的內容。

成果

https://ithelp.ithome.com.tw/upload/images/20231015/20141111kQE9Fd6FO3.png

完整程式碼範例請參考:feat/day_14/implement_blog_detail_view_using_variables


Recap

今天我們探討了如何結合 Vue Router 和 GraphQL Variables 實現動態文章詳細頁的查詢。透過 Vue 的 reactive 功能,確保了路由變更與資料查詢能夠即時同步,提供了更高的互動性和即時反應,使我們的 Web 應用體驗更佳。

明日,我們將採用分頁查詢的方式優化文章列表頁面。目前的設計會一次性呼叫全部文章 (100 篇),導致等待 API 回應時的使用者體驗不佳。不過沒關係,憑藉敏捷的精神,我們會不斷迭代和優化,直至創造出最佳的用戶體驗。


上一篇
[Day13] 魔法重構:在 Vue 專案中自動生成 GraphQL 的 TypeScript 定義
下一篇
[Day15] 實戰演練:在 Vue 中,運用 GraphQL 的魔法分頁查詢優化使用者體驗!
系列文
Vue & GraphQL 探險之旅:30天,從新手村到魔王之巔31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言