Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1import { pipe, tap } from 'wonka';
2import type { Exchange, Operation } from '@urql/core';
3
4/** Exchange factory that reexecutes operations after a user returns to the tab.
5 *
6 * @returns a new refocus {@link Exchange}.
7 *
8 * @remarks
9 * The `refocusExchange` will reexecute `Operation`s with the `cache-and-network`
10 * policy when a user switches back to your application's browser tab. This can
11 * effectively update all on-screen data when a user has stayed inactive for a
12 * long time.
13 *
14 * The `cache-and-network` policy will refetch data in the background, but will
15 * only refetch queries that are currently active.
16 */
17export const refocusExchange = (): Exchange => {
18 return ({ client, forward }) =>
19 ops$ => {
20 if (typeof window === 'undefined') {
21 return forward(ops$);
22 }
23
24 const watchedOperations = new Map<number, Operation>();
25 const observedOperations = new Map<number, number>();
26
27 window.addEventListener('visibilitychange', () => {
28 if (
29 typeof document !== 'object' ||
30 document.visibilityState === 'visible'
31 ) {
32 watchedOperations.forEach(op => {
33 client.reexecuteOperation(
34 client.createRequestOperation('query', op, {
35 ...op.context,
36 requestPolicy: 'cache-and-network',
37 })
38 );
39 });
40 }
41 });
42
43 const processIncomingOperation = (op: Operation) => {
44 if (op.kind === 'query' && !observedOperations.has(op.key)) {
45 observedOperations.set(op.key, 1);
46 watchedOperations.set(op.key, op);
47 }
48
49 if (op.kind === 'teardown' && observedOperations.has(op.key)) {
50 observedOperations.delete(op.key);
51 watchedOperations.delete(op.key);
52 }
53 };
54
55 return forward(pipe(ops$, tap(processIncomingOperation)));
56 };
57};