1import { createContext } from 'preact';
2import { useContext } from 'preact/hooks';
3import type { Client } from '@urql/core';
4
5const OBJ = {};
6
7/** `@urql/preact`'s Preact Context.
8 *
9 * @remarks
10 * The Preact Context that `urql`’s {@link Client} will be provided with.
11 * You may use the reexported {@link Provider} to provide a `Client` as well.
12 */
13export const Context: import('preact').Context<Client | object> =
14 createContext(OBJ);
15
16/** Provider for `urql`’s {@link Client} to GraphQL hooks.
17 *
18 * @remarks
19 * `Provider` accepts a {@link Client} and provides it to all GraphQL hooks,
20 * and {@link useClient}.
21 *
22 * You should make sure to create a {@link Client} and provide it with the
23 * `Provider` to parts of your component tree that use GraphQL hooks.
24 *
25 * @example
26 * ```tsx
27 * import { Provider } from '@urql/preact';
28 * // All of `@urql/core` is also re-exported by `@urql/preact`:
29 * import { Client, cacheExchange, fetchExchange } from '@urql/core';
30 *
31 * const client = new Client({
32 * url: 'https://API',
33 * exchanges: [cacheExchange, fetchExchange],
34 * });
35 *
36 * const App = () => (
37 * <Provider value={client}>
38 * <Component />
39 * </Provider>
40 * );
41 * ```
42 */
43
44export const Provider: import('preact').Provider<Client | object> =
45 Context.Provider;
46
47/** Preact Consumer component, providing the {@link Client} provided on a parent component.
48 * @remarks
49 * This is an alias for {@link Context.Consumer}.
50 */
51export const Consumer: import('preact').Consumer<Client | object> =
52 Context.Consumer;
53
54Context.displayName = 'UrqlContext';
55
56/** Hook returning a {@link Client} from {@link Context}.
57 *
58 * @remarks
59 * `useClient` is a convenience hook, which accesses `@urql/preact`'s {@link Context}
60 * and returns the {@link Client} defined on it.
61 *
62 * This will be the {@link Client} you passed to a {@link Provider}
63 * you wrapped your elements containing this hook with.
64 *
65 * @throws
66 * In development, if the component you call `useClient()` in is
67 * not wrapped in a {@link Provider}, an error is thrown.
68 */
69export const useClient = (): Client => {
70 const client = useContext(Context);
71
72 if (client === OBJ && process.env.NODE_ENV !== 'production') {
73 const error =
74 "No client has been specified using urql's Provider. please create a client and add a Provider.";
75
76 console.error(error);
77 throw new Error(error);
78 }
79
80 return client as Client;
81};