Skip to content

Commit

Permalink
Focus aware query polling
Browse files Browse the repository at this point in the history
Apollo does not support pausing polling when the current browser tab is not in focus (see [feature request](apollographql/apollo-feature-requests#247). Therefore we add our own `useFocusAwareQuery` hook that wraps `useQuery` and pauses/resumes polling upon focus/blur.
  • Loading branch information
johnnyomair committed Oct 24, 2022
1 parent c93998c commit 2ce2425
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ All notable changes to this project will be documented in this file. This projec

- Add scope support for redirects (`@comet/cms-api` and `@comet/cms-admin`)

### @comet/admin

#### Changes

- Add `useFocusAwareQuery` hook that wraps `useQuery` and only fetches when the current browser tab is focused

## 3.0.0

_Oct 17, 2022_
Expand Down
40 changes: 40 additions & 0 deletions packages/admin/admin/src/apollo/useFocusAwareQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DocumentNode, OperationVariables, QueryHookOptions, QueryResult, TypedDocumentNode, useQuery } from "@apollo/client";
import { useEffect } from "react";

function useFocusAwareQuery<TData = any, TVariables = OperationVariables>(
query: DocumentNode | TypedDocumentNode<TData, TVariables>,
options?: QueryHookOptions<TData, TVariables>,
): QueryResult<TData, TVariables> {
const queryResult = useQuery<TData, TVariables>(query, options);

const pollInterval = options?.pollInterval;
const { refetch, startPolling, stopPolling } = queryResult;

useEffect(() => {
if (pollInterval === undefined) {
return;
}

const handleFocus = () => {
refetch();

startPolling(pollInterval);
};

const handleBlur = () => {
stopPolling();
};

window.addEventListener("focus", handleFocus);
window.addEventListener("blur", handleBlur);

return () => {
window.removeEventListener("focus", handleFocus);
window.removeEventListener("blur", handleBlur);
};
}, [pollInterval, refetch, startPolling, stopPolling]);

return queryResult;
}

export { useFocusAwareQuery };
1 change: 1 addition & 0 deletions packages/admin/admin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { useFocusAwareQuery } from "./apollo/useFocusAwareQuery";
export { AppHeader, AppHeaderClassKey } from "./appHeader/AppHeader";
export { AppHeaderButton, AppHeaderButtonProps } from "./appHeader/button/AppHeaderButton";
export { AppHeaderButtonClassKey } from "./appHeader/button/AppHeaderButton.styles";
Expand Down
6 changes: 3 additions & 3 deletions packages/admin/cms-admin/src/builds/BuildEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gql, useQuery } from "@apollo/client";
import { LocalErrorScopeApolloContext } from "@comet/admin";
import { gql } from "@apollo/client";
import { LocalErrorScopeApolloContext, useFocusAwareQuery } from "@comet/admin";
import { SsgRunning, SsgStandby } from "@comet/admin-icons";
import { List, ListItem, Typography } from "@mui/material";
import { styled } from "@mui/material/styles";
Expand Down Expand Up @@ -104,7 +104,7 @@ const BuildStatusPopperContent: React.FunctionComponent<{ data: GQLBuildStatusQu
};

export function BuildEntry(): React.ReactElement {
const { data, error } = useQuery<GQLBuildStatusQuery>(buildStatusQuery, {
const { data, error } = useFocusAwareQuery<GQLBuildStatusQuery>(buildStatusQuery, {
pollInterval: process.env.NODE_ENV === "production" ? 10000 : undefined,
skip: process.env.NODE_ENV === "development",
fetchPolicy: "network-only",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gql, useQuery } from "@apollo/client";
import { Toolbar, ToolbarActions, ToolbarFillSpace } from "@comet/admin";
import { gql } from "@apollo/client";
import { Toolbar, ToolbarActions, ToolbarFillSpace, useFocusAwareQuery } from "@comet/admin";
import { ArrowRight, Close, Delete } from "@comet/admin-icons";
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, MenuItem, Select } from "@mui/material";
import { styled } from "@mui/material/styles";
Expand Down Expand Up @@ -82,7 +82,7 @@ export default function PageTreeSelectDialog({ value, onChange, open, onClose, d
const classes = useStyles();

// Fetch data
const { data } = useQuery<GQLPagesQuery, GQLPagesQueryVariables>(pagesQuery, {
const { data } = useFocusAwareQuery<GQLPagesQuery, GQLPagesQueryVariables>(pagesQuery, {
variables: {
contentScope: scope,
category,
Expand Down
16 changes: 13 additions & 3 deletions packages/admin/cms-admin/src/pages/pagesPage/PagesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { useQuery } from "@apollo/client";
import { MainContent, messages, Stack, StackPage, StackSwitch, Toolbar, ToolbarActions, useEditDialog, useStoredState } from "@comet/admin";
import {
MainContent,
messages,
Stack,
StackPage,
StackSwitch,
Toolbar,
ToolbarActions,
useEditDialog,
useFocusAwareQuery,
useStoredState,
} from "@comet/admin";
import { Add } from "@comet/admin-icons";
import { Box, Button, CircularProgress, FormControlLabel, Paper, Switch } from "@mui/material";
import withStyles from "@mui/styles/withStyles";
Expand Down Expand Up @@ -53,7 +63,7 @@ export function PagesPage({
};
}, [setRedirectPathAfterChange, path]);

const { loading, data } = useQuery<GQLPagesQuery, GQLPagesQueryVariables>(pagesQuery, {
const { loading, data } = useFocusAwareQuery<GQLPagesQuery, GQLPagesQueryVariables>(pagesQuery, {
variables: {
contentScope: scope,
category,
Expand Down

0 comments on commit 2ce2425

Please sign in to comment.