查询
获取数据涉及使用标准 GraphQL 文档执行 **查询** 操作。您可以了解更多关于查询和 GraphQL 文档的信息 这里 和 在游乐场练习运行查询。
执行查询
GraphQL 文档
让我们在本节中以这个示例 GraphQL 文档为例
query getUsers {
users {
id
firstname
lastname
email
}
}
提示
建议为您的 GraphQL 操作命名(这里为 getUsers
),这样在 Apollo Client 开发工具中更容易找到它们。
此查询将返回一个 data
对象,其中包含一个 users
数组,其中包含它们的 id
、firstname
、lastname
和 email
。它可能看起来像这样
{
"data": {
"users": [
{
"id": "abc",
"firstname": "James",
"lastname": "Holden",
"email": "james.holden@roci.com"
},
{
"id": "def",
"firstname": "Naomi",
"lastname": "Nagata",
"email": "naomi.nagata@roci.com"
}
]
}
}
您可能会问:为什么 data
上有一个嵌套的 users
属性?为什么数组不直接在 data
上?
这是因为您可以在 GraphQL 操作中选择多个根字段
query getCatsAndDogs {
cats {
id
}
dogs {
id
}
}
在这种情况下,结果可能看起来像这样
{
"data": {
"cats": [
{ "id": "abc" },
{ "id": "def" }
],
"dogs": [
{ "id": "ghi" },
{ "id": "jkl" }
]
}
}
结果中还可能存在除 data
之外的其他可选属性
errors
:服务器返回的错误数组extensions
:其他信息,例如执行时间
useQuery
用于执行查询的主要组合函数是 useQuery
。在您的组件中,首先导入它
<script>
import { useQuery } from '@vue/apollo-composable'
export default {
setup () {
// Your data & logic here...
},
}
</script>
您可以在 setup
选项中使用 useQuery
,并将 GraphQL 文档作为第一个参数传递给它。然后检索查询 result
<script>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
},
}
</script>
请注意,这里的 result
是一个 Ref
,它保存了 Apollo 返回的结果中的数据。
如果您想直接访问数据对象,请使用 result.value
<script>
import { watch } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
watch(() => {
console.log(result.value)
})
},
}
</script>
在这个例子中,您也可以直接观察 Ref
<script>
import { watch } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
watch(result, value => {
console.log(value)
})
},
}
</script>
让我们在模板中公开我们的结果
<script>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
return {
result,
}
},
}
</script>
<template>
<ul>
<li v-for="user of result.users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
请注意,result
可能并不总是包含您的数据!它最初将是 undefined
,直到查询成功完成。因此,在渲染数据之前添加一个条件是一个好主意
<template>
<ul v-if="result && result.users">
<li v-for="user of result.users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
我们可以使用一个 computed
属性来简化对结果部分的访问,并提供一个默认值
<script>
import { computed } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
const users = computed(() => result.value?.users ?? [])
return {
users,
}
},
}
</script>
<template>
<ul>
<li v-for="user of users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
查询状态
加载状态
除了 result
之外,useQuery
还返回 loading
,这是一个布尔 Ref
,用于跟踪查询的加载状态
<script>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result, loading } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
return {
result,
loading,
}
},
}
</script>
<template>
<div v-if="loading">Loading...</div>
<ul v-else-if="result && result.users">
<li v-for="user of result.users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
错误
还有一个 error
Ref
,它保存了请求过程中可能发生的任何错误
<script>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result, loading, error } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
return {
result,
loading,
error,
}
},
}
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<ul v-else-if="result && result.users">
<li v-for="user of result.users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
变量
您可以将 variables
对象传递给 useQuery
的第二个参数
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, {
id: 'abc-abc-abc',
})
变量 Ref
您可以通过检索它们的 variables
Ref
来稍后更改它们
const { result, variables } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, {
id: 'abc-abc-abc',
})
function selectUser (id) {
variables.value = {
id,
}
}
提示
这将每次 variables
对象中的属性更改时重新获取查询。
或者,您可以直接传递一个 Ref
import { ref } from 'vue'
const variables = ref({
id: 'abc-abc-abc',
})
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, variables)
function selectUser (id) {
variables.value = {
id,
}
}
响应式对象
您还可以传递一个响应式对象
import { reactive } from 'vue'
const variables = reactive({
id: 'abc-abc-abc',
})
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, variables)
function selectUser (id) {
variables.id = id
}
这也意味着您可以直接传递 setup
中的 props
,因为 props
已经是响应式对象
export default {
props: ['id'],
setup (props) {
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, props)
return {
result,
}
},
}
但请注意,如果您添加了 GraphQL 文档中未使用的新的 props
,您将遇到 GraphQL 验证错误!
变量函数
最后,您可以将变量作为返回对象的函数传递
export default {
props: ['id'],
setup (props) {
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, () => ({
id: props.id,
}))
return {
result,
}
},
}
此变量函数将自动变为响应式,因此每当 props.id
更改时,查询的 variables
对象都会更新。
此语法在您想在 variables
中使用一些 Ref
时也很有用
const id = ref('abc-abc-abc')
const { result } = useQuery(gql`
query getUserById ($id: ID!) {
user (id: $id) {
id
email
}
}
`, () => ({
id: id.value
}))
function selectUser (id) {
id.value = id
}
选项
useQuery
的第三个参数是一个选项对象,用于配置您的查询。
与 variables
一样,您可以传递一个 Ref
、一个响应式对象或一个将自动变为响应式的函数。
使用 Ref
const options = ref({
fetchPolicy: 'cache-first',
})
const { result } = useQuery(gql`
query getUsers {
users {
id
email
}
}
`, null, options)
使用响应式对象
const options = reactive({
fetchPolicy: 'cache-first',
})
const { result } = useQuery(gql`
query getUsers {
users {
id
email
}
}
`, null, options)
使用将自动变为响应式的函数
const fetchPolicy = ref('cache-first')
const { result } = useQuery(gql`
query getUsers {
users {
id
email
}
}
`, null, () => ({
fetchPolicy: fetchPolicy.value
}))
有关所有可能的选项,请参阅 API 参考。
禁用查询
您可以使用 enabled
选项禁用和重新启用查询
const enabled = ref(false)
const { result } = useQuery(gql`
...
`, null, () => ({
enabled: enabled.value,
}))
function enableQuery () {
enabled.value = true
}
获取策略
fetchPolicy
选项允许您自定义查询将如何使用 Apollo Client 缓存。
const { result } = useQuery(gql`
...
`, null, {
fetchPolicy: 'cache-and-network',
})
可用值是
cache-first
(默认):从缓存中返回结果。仅当缓存结果不可用时才从网络获取。cache-and-network
:首先从缓存中返回结果(如果存在),然后在网络结果可用时返回网络结果。cache-only
:如果可用,则从缓存中返回结果,否则失败。network-only
:从网络返回结果,如果网络调用不成功则失败,保存到缓存。no-cache
:从网络返回结果,如果网络调用不成功则失败,不保存到缓存。
更新缓存结果
查询完成后,它将使用结果数据更新缓存(取决于 获取策略)。这提高了下次在应用程序中需要渲染数据时的性能,并确保依赖于数据的所有组件始终保持一致。
但是,您有时希望确保此数据与服务器相比是最新的。
轮询
轮询意味着反复调用服务器以自动更新查询数据。
您可以使用 pollInterval
启用轮询,它将是每次重复向服务器发出的请求之间的间隔(以毫秒为单位)。
在这个例子中,我们将每秒轮询服务器一次
const { result } = useQuery(gql`
...
`, null, {
pollInterval: 1000,
})
重新获取
另一种方法是在响应事件时手动再次执行查询,而不是使用固定间隔。
这是使用 refetch
函数完成的
<script>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result, loading, error, refetch } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
const users = computed(() => result.value?.users)
return {
users,
loading,
error,
refetch,
}
},
}
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<ul v-else-if="users">
<li v-for="user of users" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
<button @click="refetch()">Refresh</button>
</ul>
</template>
事件钩子
useQuery
返回事件钩子,允许您在发生特定事件时执行代码。
onResult
每当有新结果可用时,就会调用它。
const { onResult } = useQuery(...)
onResult(queryResult => {
console.log(queryResult.data)
console.log(queryResult.loading)
console.log(queryResult.networkStatus)
console.log(queryResult.stale)
})
您可以传递 notifyOnNetworkStatusChange
选项以强制查询在网络状态或错误更新时触发新结果
useQuery(gql`
...
`, null, {
notifyOnNetworkStatusChange: true,
})
onError
它在发生错误时触发
const { onError } = useQuery(...)
onError(error => {
console.log(error.graphQLErrors)
console.log(error.networkError)
})
您可以使用 @vue/apollo-util
包中的 logErrorMessages
函数来格式化浏览器控制台中的错误
import { logErrorMessages } from '@vue/apollo-util'
const { onError } = useQuery(...)
onError(error => {
logErrorMessages(error)
})
示例错误
如果您使用的是 Webpack 或 Vue CLI,最好只在开发中使用它
import { logErrorMessages } from '@vue/apollo-util'
const { onError } = useQuery(...)
onError(error => {
if (process.env.NODE_ENV !== 'production') {
logErrorMessages(error)
}
})
这样,在为生产编译项目时,它将被删除。
延迟查询
如果您需要等待才能开始查询,可以使用 useLazyQuery
而不是 useQuery
。它返回一个额外的 load
函数来启动查询您的 API。
示例
<script>
import { computed } from 'vue'
import gql from 'graphql-tag'
import { useLazyQuery } from '@vue/apollo-composable'
export default {
setup () {
const { result, load } = useLazyQuery(gql`
query list {
list
}
`)
const list = computed(() => result.value?.list ?? [])
return {
load,
list,
}
},
}
</script>
<template>
<div class="m-6">
<button
class="bg-green-200 rounded-lg p-4"
@click="load()"
>
Load list
</button>
<ul class="my-4">
<li
v-for="(item, index) of list"
:key="index"
class="list-disc ml-6"
>
{{ item }}
</li>
</ul>
</div>
</template>
获取结果
load()
返回一个 Promise,用于获取第一次请求的结果(如果这是第一次激活查询)。
const { result, load, refetch } = useLazyQuery(gql`
query list {
list
}
`)
// ...
async function myLoad () {
try {
const result = await load()
} catch (e) {
// Handle error
}
}
重新获取延迟查询
如果这不是第一次激活查询,load()
将返回 false
。您可以使用它来使用 refetch()
重新获取查询,以防用户再次单击按钮,这意味着 load()
返回 false
。
const { result, load, refetch } = useLazyQuery(gql`
query list {
list
}
`)
// ...
function loadOrRefetch () {
load() || refetch()
}