feat: deprecate useResult

This commit is contained in:
Guillaume Chau
2022-05-02 17:41:48 +02:00
parent d6d4da16d5
commit 0e9fb48384
2 changed files with 50 additions and 204 deletions
+39 -204
View File
@@ -231,6 +231,45 @@ Beware that `result` may not contain your data at all time! It will initially be
</template>
```
We can use a `computed` prop to simplify access to part of the result and to provide a default value:
```vue{2,19,22,30}
<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>
```
## Query status
### Loading state
@@ -318,210 +357,6 @@ export default {
</template>
```
## useResult
The sister composition function `useResult` is available alongside `useQuery` to facilitate usage of the query `result`.
### Result picking
The first useful feature of `useResult` is picking one object from the result data. To do so, pass the `result` data as the first parameter, and a picking function as the third parameter:
```vue{2,18,21,34,35}
<script>
import { useQuery, useResult } 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
}
}
`)
const users = useResult(result, null, data => data.users)
return {
users,
loading,
error,
}
},
}
</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>
</ul>
</template>
```
This is very useful if the data relevant to your component is nested in the query:
```js
const { result } = useQuery(gql`
query getMessages {
currentUser {
messages {
id
text
}
}
}
`)
const messages = useResult(result, null, data => data.currentUser.messages)
```
Another perk of `useResult` is that the picking function will silence errors inside the picking function. For example, if `result.value` is `undefined`, you don't have to add additional checks:
```js
// You don't need to do this!
const messages = useResult(result, null, data => data && data.currentUser && data.currentUser.messages)
// Instead do this:
const messages = useResult(result, null, data => data.currentUser.messages)
```
::: tip
Don't forget that `messages.value` can still be `null` until the query successfully completes!
:::
Another use case where `useResult` proves to be very useful is when you have multiple objects on the result data:
```js
const { result } = useQuery(gql`
query getUsersAndPosts {
users {
id
email
}
posts {
id
title
}
}
`)
const users = useResult(result, null, data => data.users)
const posts = useResult(result, null, data => data.posts)
```
Look how we cleanly separated the result data into two different `Ref`!
### Automatic picking
If there is only one object in the data, `useResult` will automatically try to pick the object:
```js{12}
const { result, loading } = useQuery(gql`
query getUsers {
users {
id
firstname
lastname
email
}
}
`)
const users = useResult(result)
```
Here `users.value` will be the `users` array retrieved from our server.
### Default value
Let's say we want to sort our users on their last names:
```vue{2,19-21,24,34,35}
<script>
import { computed } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
export default {
setup () {
const { result, loading } = useQuery(gql`
query users {
users {
id
firstname
lastname
email
}
}
`)
const sortedUsers = computed(() => result.value.users.sort(
(a, b) => a.lastname.localeCompare(b.lastname)
))
return {
sortedUsers,
loading,
}
},
}
</script>
<template>
<div v-if="loading">Loading...</div>
<ul v-else-if="sortedUsers">
<li v-for="user of sortedUsers" :key="user.id">
{{ user.firstname }} {{ user.lastname }}
</li>
</ul>
</template>
```
Here we will run into an error because `result.value` can be `undefined` (and potentially `result.value.users` can also be `undefined`). So the `sort` method will throw an error when called in our `computed` property.
We could add checks, but it can rapidly become tedious:
```js
const sortedUsers = computed(() => result.value && result.value.users ? result.value.users.sort(
(a, b) => a.lastname.localeCompare(b.lastname)
) : [])
```
We can further simplify this with `useResult`:
```js{1,3,5}
const users = useResult(result) // Automatically picked
const sortedUsers = computed(() => users.value ? users.value.sort(
(a, b) => a.lastname.localeCompare(b.lastname)
) : [])
```
But we can eliminate the conditional entirely if we pass a default value as the 2nd parameter of `useResult`:
```js{1,3,5}
const users = useResult(result, []) // Defaults to an empty array
const sortedUsers = computed(() => users.value.sort(
(a, b) => a.lastname.localeCompare(b.lastname)
))
```
This is even more useful if we want to use the `users` array `Ref` in multiple places in our `setup` function!
## Variables
You can pass a `variables` object to the 2nd parameter of `useQuery`:
@@ -16,6 +16,7 @@ export type UseResultReturn<T> = Readonly<Ref<Readonly<T>>>
*
* @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.
* @returns Readonly ref with `undefined` or the resolved `result`.
* @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`
*/
export function useResult<TResult, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>> (
result: Ref<TResult>
@@ -34,6 +35,7 @@ export function useResult<TResult, TResultKey extends keyof NonNullable<TResult>
* @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.
* @param {TDefaultValue} defaultValue The default return value before `result` is resolved.
* @returns Readonly ref with the `defaultValue` or the resolved `result`.
* @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`
*/
export function useResult<TResult, TDefaultValue, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>> (
result: Ref<TResult>,
@@ -53,6 +55,7 @@ export function useResult<TResult, TDefaultValue, TResultKey extends keyof NonNu
* @param {TDefaultValue} defaultValue The default return value before `result` is resolved.
* @param {(data:TResult)=>TReturnValue} pick The function that receives `result` and maps a return value from it.
* @returns Readonly ref with the `defaultValue` or the resolved and `pick`-mapped `result`
* @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`
*/
export function useResult<
TResult,
@@ -64,6 +67,9 @@ export function useResult<
pick: (data: DeepRequired<DeepNonNullable<TResult>>) => TReturnValue
): UseResultReturn<TDefaultValue | TReturnValue>
/**
* @deprecated Use `computed` instead. Before: `const items = useResult(result, [], data => data.someField.myItems)` After: `const items = computed(() => result.value?.someField.myItems ?? [])`
*/
export function useResult<
TResult,
TDefaultValue,
@@ -73,6 +79,11 @@ export function useResult<
defaultValue?: TDefaultValue,
pick?: (data: DeepRequired<DeepNonNullable<TResult>>) => TReturnValue,
): UseResultReturn<TResult | TResult[keyof TResult] | TDefaultValue | TReturnValue | undefined> {
console.warn(`'useResult' is deprecated and will be removed soon. Plase use a computed instead.
Before:
const items = useResult(result, [], data => data.someField.myItems)
After:
const items = computed(() => result.value?.someField.myItems ?? [])`)
return computed(() => {
const value = result.value
if (value) {