Smart Query 與 Smart Subscription 雖然方便,但必須在 apollo
先宣告 Query 也順便定義其 GraphQL,且在 Component 載入時自動執行;若想在某個 Event 下執行 GraphQL,則要改用 Dynamic Query 與 Dynamic Subscription 動態載入 GraphQL。
Version
macOS Catalina 10.15.2
WebStorm 2019.3
Node 13.2.0
Vue CLI 4.1.1
Vue 2.6.10
Vue Apollo 3.0.0-beta.11
Vue Apollo
src/App.vue
<template>
<div>
<ul>
<li v-for="(item, index) in books" :key="index">
{{ item.title }}:{{ item.price }}
</li>
</ul>
</div>
</template>
<script>
import gql from 'graphql-tag'
let query = gql`
query {
books {
title
price
}
}
`
let subscription = gql`
subscription {
bookAdded {
title
price
}
}
`
let mounted = function() {
this.$apollo
.query({ query })
.then(x => this.books = x.data.books)
let next = ({ data: { bookAdded }}) => this.books = [...this.books, bookAdded]
this.$apollo
.subscribe({ query: subscription })
.subscribe({ next })
}
export default {
name: 'app',
data: () => ({
books: []
}),
mounted
}
</script>
44 行
export default {
name: 'app',
data: () => ({
books: []
}),
mounted
}
並沒有在 apollo
property 下定義 books
smart query,而是改用傳統 books
data。
32 行
let mounted = function() {
this.$apollo
.query({ query })
.then(x => this.books = x.data.books)
let next = ({ data: { bookAdded }}) => this.books = [...this.books, bookAdded]
this.$apollo
.subscribe({ query: subscription })
.subscribe({ next })
}
所有 query 與 subscription 都會動態寫在 mounted
hooks 內。
33 行
this.$apollo
.query({ query })
.then(x => this.books = x.data.books)
以 this.$apollo
讀取 Apollo Client,在其 query()
傳入由 query
組成的 object 產生 dynamic query。
由於 query()
回傳為 promise,可自行在 then()
的 callback 中以 side effect 寫入到 books
data,也可使用 promise 的 catch()
與 finally()
做進一步處理。
14 行
let query = gql`
query {
books {
title
price
}
}
`
定義 dynamic query 所使用的 GraphQL query。
37 行
let next = ({ data: { bookAdded }}) => this.books = [...this.books, bookAdded]
this.$apollo
.subscribe({ query: subscription })
.subscribe({ next })
以 this.$apollo
讀取 Apollo Client,在其 subscribe()
傳入由 query
組成的 object 產生 dynamic subscription。
因為 query
在 dynamic query 已經使用過,因此改用 subscription
取 alias。
不過 subscribe()
並不是回傳 promise,若要回應 subscription 回傳的資料,必須再呼叫一次 subscribe()
,並傳入 next()
為 property 的 function 回應 subscription。
可直接在 next()
的 argument 解構 subscription 回傳的資料,然後直接修改 books
data。
23 行
let subscription = gql`
subscription {
bookAdded {
title
price
}
}
`
定義 dynamic subscription 所使用的 GraphQL subscription。
Async Await
let mounted = async function() {
let { data: { books }} = await this.$apollo.query({ query })
this.books = books
let next = ({ data: { bookAdded }}) => this.books = [...this.books, bookAdded]
this.$apollo
.subscribe({ query: subscription })
.subscribe({ next })
}
由於 this.$apollo.query()
回傳 promise,因此也可以使用 async await 修改 books
data。
Browser
原本 books
data 只有 2
筆資料。
Insomnia
mutation {
addBook(book: {
title: "Speaking JavaScript"
price: 300
}) {
title
price
}
}
使用 Insomnia 執行 addBook
mutation,相當於在其他 client 執行 mutation 觸發 subscription。
Browser
原本 books
data 自動更新成 3
筆資料。
Conclusion
- Vue Apollo 讓我在收到 GraphQL subscription 後,不用再重新執行 GraphQL Query,只要實踐
next()
即可自動在背景更新原本資料,非常方便
Sample Code
完整範例可在我的 GitHub 上找到