-
-
Notifications
You must be signed in to change notification settings - Fork 450
/
useClient.ts
120 lines (111 loc) · 3.5 KB
/
useClient.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import type { App, Ref } from 'vue';
import { getCurrentInstance, inject, provide, isRef, shallowRef } from 'vue';
import type { ClientOptions } from '@urql/core';
import { Client } from '@urql/core';
const clientsPerInstance = new WeakMap<{}, Ref<Client>>();
/** Provides a {@link Client} to a component’s children.
*
* @param opts - {@link ClientOptions}, a {@link Client}, or a reactive ref object of a `Client`.
*
* @remarks
* `provideClient` provides a {@link Client} to `@urql/vue`’s GraphQL
* functions in children components.
*
* Hint: GraphQL functions and {@link useClient} will see the
* provided `Client`, even if `provideClient` has been called
* in the same component’s `setup` function.
*
* @example
* ```ts
* import { provideClient } from '@urql/vue';
* // All of `@urql/core` is also re-exported by `@urql/vue`:
* import { Client, cacheExchange, fetchExchange } from '@urql/core';
*
* export default {
* setup() {
* provideClient(new Client({
* url: 'https://API',
* exchanges: [cacheExchange, fetchExchange],
* }));
* },
* };
* ```
*/
export function provideClient(opts: ClientOptions | Client | Ref<Client>) {
let client: Ref<Client>;
if (!isRef(opts)) {
client = shallowRef(opts instanceof Client ? opts : new Client(opts));
} else {
client = opts;
}
const instance = getCurrentInstance();
if (instance) {
clientsPerInstance.set(instance, client);
}
provide('$urql', client);
return client.value;
}
/** Provides a {@link Client} to a Vue app.
*
* @param app - the Vue {@link App}
* @param opts - {@link ClientOptions}, a {@link Client}, or a reactive ref object of a `Client`.
*
* @remarks
* `install` provides a {@link Client} to `@urql/vue`’s GraphQL
* functions in a Vue app.
*
* @example
* ```ts
* import * as urql from '@urql/vue';
* // All of `@urql/core` is also re-exported by `@urql/vue`:
* import { cacheExchange, fetchExchange } from '@urql/core';
*
* import { createApp } from 'vue';
* import Root from './App.vue';
*
* const app = createApp(Root);
* app.use(urql, {
* url: 'http://localhost:3000/graphql',
* exchanges: [cacheExchange, fetchExchange],
* });
* ```
*/
export function install(app: App, opts: ClientOptions | Client | Ref<Client>) {
let client: Ref<Client>;
if (!isRef(opts)) {
client = shallowRef(opts instanceof Client ? opts : new Client(opts));
} else {
client = opts;
}
app.provide('$urql', client);
}
/** Returns a provided reactive ref object of a {@link Client}.
*
* @remarks
* `useClient` may be called in Vue `setup` functions to retrieve a
* reactive rev object of a {@link Client} that’s previously been
* provided with {@link provideClient} in the current or a parent’s
* `setup` function.
*
* @throws
* In development, if `useClient` is called outside of a Vue `setup`
* function or no {@link Client} was provided, an error will be thrown.
*/
export function useClient(): Ref<Client> {
const instance = getCurrentInstance();
if (process.env.NODE_ENV !== 'production' && !instance) {
throw new Error(
'use* functions may only be called during the `setup()` or other lifecycle hooks.'
);
}
let client = inject('$urql') as Ref<Client> | undefined;
if (!client && instance) {
client = clientsPerInstance.get(instance);
}
if (process.env.NODE_ENV !== 'production' && !client) {
throw new Error(
'No urql Client was provided. Did you forget to install the plugin or call `provideClient` in a parent?'
);
}
return client!;
}