feat: new context params in event hook handlers
Allow easy access to the client, especially useful with useSubscription().
This commit is contained in:
@@ -47,6 +47,6 @@
|
||||
|
||||
- `called`: boolean `Ref` holding `true` if the mutation was already called.
|
||||
|
||||
- `onDone`: Event hook called when the mutation successfully completes.
|
||||
- `onDone(handler)`: Event hook called when the mutation successfully completes. Handler is called with: `result` (mutation result) and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
- `onError`: Event hook called when an error occurs.
|
||||
- `onError(handler)`: Event hook called when an error occurs. Handler is called with: `error` and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
- `subscribeToMore(options)`: Add a subscription to the query, useful to add new data received from the server in real-time. See [Subscription](../guide-composable/subscription#subscribetomore).
|
||||
|
||||
- `onResult(handler)`: Event hook called when a new result is available.
|
||||
- `onResult(handler)`: Event hook called when a new result is available. Handler is called with: `result` (query result) and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
- `onError(handler)`: Event hook called when an error occurs.
|
||||
- `onError(handler)`: Event hook called when an error occurs. Handler is called with: `error` and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
- `variables`: Ref holding the variables object.
|
||||
|
||||
- `onResult(handler)`: Event hook called when a new result is available.
|
||||
- `onResult(handler)`: Event hook called when a new result is available. Handler is called with: `result` (new result) and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
- `onError(handler)`: Event hook called when an error occurs.
|
||||
- `onError(handler)`: Event hook called when an error occurs. Handler is called with: `error` and `context` which is an object with `client` (ApolloClient instance).
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@ This is called when a new result is received from the server:
|
||||
```js
|
||||
const { onResult } = useSubscription(...)
|
||||
|
||||
onResult(result => {
|
||||
onResult((result, context) => {
|
||||
console.log(result.data)
|
||||
})
|
||||
```
|
||||
@@ -417,11 +417,48 @@ import { logErrorMessages } from '@vue/apollo-util'
|
||||
|
||||
const { onError } = useSubscription(...)
|
||||
|
||||
onError(error => {
|
||||
onError((error, context) => {
|
||||
logErrorMessages(error)
|
||||
})
|
||||
```
|
||||
|
||||
### Update the cache
|
||||
|
||||
Using `onResult`, you can update the Apollo cache with the new data:
|
||||
|
||||
```js
|
||||
const { onResult } = useSubscription(...)
|
||||
|
||||
onResult((result, { client }) => {
|
||||
const query = {
|
||||
query: gql`query getMessages ($channelId: ID!) {
|
||||
messages(channelId: $channelId) {
|
||||
id
|
||||
text
|
||||
}
|
||||
}`,
|
||||
variables: {
|
||||
channelId: '123',
|
||||
},
|
||||
}
|
||||
|
||||
// Read the query
|
||||
let data = client.readQuery(query)
|
||||
|
||||
// Update cached data
|
||||
data = {
|
||||
...data,
|
||||
messages: [...data.messages, result.data.messageAdded],
|
||||
}
|
||||
|
||||
// Write back the new result for the query
|
||||
client.writeQuery({
|
||||
...query,
|
||||
data,
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## subscribeToMore
|
||||
|
||||
With GraphQL subscriptions your client will be alerted on push from the server and you should choose the pattern that fits your application the most:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DocumentNode } from 'graphql'
|
||||
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode, ApolloError } from '@apollo/client/core/index.js'
|
||||
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode, ApolloError, ApolloClient } from '@apollo/client/core/index.js'
|
||||
import { ref, onBeforeUnmount, isRef, Ref, getCurrentInstance } from 'vue-demi'
|
||||
import { useApolloClient } from './useApolloClient'
|
||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||
@@ -25,15 +25,23 @@ export type MutateOverrideOptions<TResult> = Pick<UseMutationOptions<TResult, Op
|
||||
export type MutateResult<TResult> = Promise<FetchResult<TResult, Record<string, any>, Record<string, any>> | null>
|
||||
export type MutateFunction<TResult, TVariables> = (variables?: TVariables | null, overrideOptions?: MutateOverrideOptions<TResult>) => MutateResult<TResult>
|
||||
|
||||
export interface OnDoneContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
export interface OnErrorContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
export interface UseMutationReturn<TResult, TVariables> {
|
||||
mutate: MutateFunction<TResult, TVariables>
|
||||
loading: Ref<boolean>
|
||||
error: Ref<ApolloError | null>
|
||||
called: Ref<boolean>
|
||||
onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||
onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>, context: OnDoneContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
onError: (fn: (param: ApolloError) => void) => {
|
||||
onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
}
|
||||
@@ -51,8 +59,8 @@ export function useMutation<
|
||||
const error = ref<ApolloError | null>(null)
|
||||
const called = ref<boolean>(false)
|
||||
|
||||
const doneEvent = useEventHook<FetchResult<TResult, Record<string, any>, Record<string, any>>>()
|
||||
const errorEvent = useEventHook<ApolloError>()
|
||||
const doneEvent = useEventHook<[FetchResult<TResult, Record<string, any>, Record<string, any>>, OnDoneContext]>()
|
||||
const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()
|
||||
|
||||
// Apollo Client
|
||||
const { resolveClient } = useApolloClient()
|
||||
@@ -92,13 +100,17 @@ export function useMutation<
|
||||
: undefined,
|
||||
})
|
||||
loading.value = false
|
||||
doneEvent.trigger(result)
|
||||
doneEvent.trigger(result, {
|
||||
client,
|
||||
})
|
||||
return result
|
||||
} catch (e) {
|
||||
const apolloError = toApolloError(e)
|
||||
error.value = apolloError
|
||||
loading.value = false
|
||||
errorEvent.trigger(apolloError)
|
||||
errorEvent.trigger(apolloError, {
|
||||
client,
|
||||
})
|
||||
if (currentOptions.throws === 'always' || (currentOptions.throws !== 'never' && !errorEvent.getCount())) {
|
||||
throw apolloError
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import type {
|
||||
ObservableSubscription,
|
||||
TypedDocumentNode,
|
||||
ApolloError,
|
||||
ApolloClient,
|
||||
} from '@apollo/client/core/index.js'
|
||||
import { throttle, debounce } from 'throttle-debounce'
|
||||
import { useApolloClient } from './useApolloClient'
|
||||
@@ -58,6 +59,14 @@ export type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<Document
|
||||
export type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>
|
||||
export type OptionsParameter<TResult, TVariables extends OperationVariables> = UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>> | ReactiveFunction<UseQueryOptions<TResult, TVariables>>
|
||||
|
||||
export interface OnResultContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
export interface OnErrorContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
// Return
|
||||
export interface UseQueryReturn<TResult, TVariables extends OperationVariables> {
|
||||
result: Ref<TResult | undefined>
|
||||
@@ -75,10 +84,10 @@ export interface UseQueryReturn<TResult, TVariables extends OperationVariables>
|
||||
refetch: (variables?: TVariables) => Promise<ApolloQueryResult<TResult>> | undefined
|
||||
fetchMore: (options: FetchMoreQueryOptions<TVariables, TResult> & FetchMoreOptions<TResult, TVariables>) => Promise<ApolloQueryResult<TResult>> | undefined
|
||||
subscribeToMore: <TSubscriptionVariables = OperationVariables, TSubscriptionData = TResult>(options: SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData> | Ref<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>> | ReactiveFunction<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>>) => void
|
||||
onResult: (fn: (param: ApolloQueryResult<TResult>) => void) => {
|
||||
onResult: (fn: (param: ApolloQueryResult<TResult>, context: OnResultContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
onError: (fn: (param: ApolloError) => void) => {
|
||||
onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
}
|
||||
@@ -157,9 +166,9 @@ export function useQueryImpl<
|
||||
* Result from the query
|
||||
*/
|
||||
const result = ref<TResult | undefined>()
|
||||
const resultEvent = useEventHook<ApolloQueryResult<TResult>>()
|
||||
const resultEvent = useEventHook<[ApolloQueryResult<TResult>, OnResultContext]>()
|
||||
const error = ref<ApolloError | null>(null)
|
||||
const errorEvent = useEventHook<ApolloError>()
|
||||
const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()
|
||||
|
||||
// Loading
|
||||
|
||||
@@ -217,6 +226,10 @@ export function useQueryImpl<
|
||||
// Apollo Client
|
||||
const { resolveClient } = useApolloClient()
|
||||
|
||||
function getClient () {
|
||||
return resolveClient(currentOptions.value?.clientId)
|
||||
}
|
||||
|
||||
// Query
|
||||
|
||||
const query: Ref<ObservableQuery<TResult, TVariables> | null | undefined> = shallowRef()
|
||||
@@ -242,7 +255,7 @@ export function useQueryImpl<
|
||||
error.value = null
|
||||
loading.value = true
|
||||
|
||||
const client = resolveClient(currentOptions.value?.clientId)
|
||||
const client = getClient()
|
||||
|
||||
query.value = client.watchQuery<TResult, TVariables>({
|
||||
query: currentDocument,
|
||||
@@ -328,7 +341,9 @@ export function useQueryImpl<
|
||||
networkStatus.value = queryResult.networkStatus
|
||||
// Wait for handlers to be registered
|
||||
nextTick(() => {
|
||||
resultEvent.trigger(queryResult)
|
||||
resultEvent.trigger(queryResult, {
|
||||
client: getClient(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -357,7 +372,9 @@ export function useQueryImpl<
|
||||
networkStatus.value = 8
|
||||
// Wait for handlers to be registered
|
||||
nextTick(() => {
|
||||
errorEvent.trigger(apolloError)
|
||||
errorEvent.trigger(apolloError, {
|
||||
client: getClient(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
ObservableSubscription,
|
||||
TypedDocumentNode,
|
||||
ApolloError,
|
||||
ApolloClient,
|
||||
} from '@apollo/client/core/index.js'
|
||||
import { throttle, debounce } from 'throttle-debounce'
|
||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||
@@ -44,6 +45,14 @@ type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode> |
|
||||
type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>
|
||||
type OptionsParameter<TResult, TVariables> = UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>> | ReactiveFunction<UseSubscriptionOptions<TResult, TVariables>>
|
||||
|
||||
export interface OnResultContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
export interface OnErrorContext {
|
||||
client: ApolloClient<any>
|
||||
}
|
||||
|
||||
export interface UseSubscriptionReturn<TResult, TVariables> {
|
||||
result: Ref<TResult | null | undefined>
|
||||
loading: Ref<boolean>
|
||||
@@ -55,10 +64,10 @@ export interface UseSubscriptionReturn<TResult, TVariables> {
|
||||
variables: Ref<TVariables | undefined>
|
||||
options: UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>>
|
||||
subscription: Ref<Observable<FetchResult<TResult, Record<string, any>, Record<string, any>>> | null>
|
||||
onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||
onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>, context: OnResultContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
onError: (fn: (param: ApolloError) => void) => {
|
||||
onError: (fn: (param: ApolloError, context: OnErrorContext) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
}
|
||||
@@ -119,9 +128,9 @@ export function useSubscription <
|
||||
const optionsRef = paramToReactive(options)
|
||||
|
||||
const result = ref<TResult | null | undefined>()
|
||||
const resultEvent = useEventHook<FetchResult<TResult>>()
|
||||
const resultEvent = useEventHook<[FetchResult<TResult>, OnResultContext]>()
|
||||
const error = ref<ApolloError | null>(null)
|
||||
const errorEvent = useEventHook<ApolloError>()
|
||||
const errorEvent = useEventHook<[ApolloError, OnErrorContext]>()
|
||||
|
||||
const loading = ref(false)
|
||||
vm && trackSubscription(loading)
|
||||
@@ -133,12 +142,16 @@ export function useSubscription <
|
||||
let observer: ObservableSubscription | null = null
|
||||
let started = false
|
||||
|
||||
function getClient () {
|
||||
return resolveClient(currentOptions.value?.clientId)
|
||||
}
|
||||
|
||||
function start () {
|
||||
if (started || !isEnabled.value || isServer) return
|
||||
started = true
|
||||
loading.value = true
|
||||
|
||||
const client = resolveClient(currentOptions.value?.clientId)
|
||||
const client = getClient()
|
||||
|
||||
subscription.value = client.subscribe<TResult, TVariables>({
|
||||
query: currentDocument,
|
||||
@@ -155,7 +168,9 @@ export function useSubscription <
|
||||
function onNextResult (fetchResult: FetchResult<TResult>) {
|
||||
result.value = fetchResult.data
|
||||
loading.value = false
|
||||
resultEvent.trigger(fetchResult)
|
||||
resultEvent.trigger(fetchResult, {
|
||||
client: getClient(),
|
||||
})
|
||||
}
|
||||
|
||||
function onError (fetchError: unknown) {
|
||||
@@ -163,7 +178,9 @@ export function useSubscription <
|
||||
|
||||
error.value = apolloError
|
||||
loading.value = false
|
||||
errorEvent.trigger(apolloError)
|
||||
errorEvent.trigger(apolloError, {
|
||||
client: getClient(),
|
||||
})
|
||||
}
|
||||
|
||||
function stop () {
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
export function useEventHook<TParam = any> () {
|
||||
const fns: Array<(param: TParam) => void> = []
|
||||
export function useEventHook<TParams extends any[] = any[]> () {
|
||||
const fns: Array<(...params: TParams) => void> = []
|
||||
|
||||
function on (fn: (param: TParam) => void) {
|
||||
function on (fn: (...params: TParams) => void) {
|
||||
fns.push(fn)
|
||||
return {
|
||||
off: () => off(fn),
|
||||
}
|
||||
}
|
||||
|
||||
function off (fn: (param: TParam) => void) {
|
||||
function off (fn: (...params: TParams) => void) {
|
||||
const index = fns.indexOf(fn)
|
||||
if (index !== -1) {
|
||||
fns.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function trigger (param: TParam) {
|
||||
function trigger (...params: TParams) {
|
||||
for (const fn of fns) {
|
||||
fn(param)
|
||||
fn(...params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user