-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Window Focus Refetching #247
Comments
I made a CodeSandbox showing the basic behavior of the feature. |
+1 for adding this feature. It's very neat and optimized. |
+1 for this feature as well. |
+1 |
Would also love to see this feature. |
This would be a great one! |
It's a nice to have imo since you can do this quite simply with javascript. There's a good example here: https://spectrum.chat/apollo/apollo-client/how-do-i-refetch-a-query-on-window-focus-with-react-js-next-js~aff68732-35f7-4c04-aa98-e8b66ff096f3
|
@Kae7in It's not just about fetching on refocus. The polling has to stop when the tab is not focused, and the polling sequence should start again on refocus. |
+1 on this feature |
2 similar comments
+1 on this feature |
+1 on this feature |
I found success in React with something like this:
When the user navigates away from the browser tab in which your website is open, the query should stop polling altogether. When the user navigates back, it should once again start. So far I've only tested on my macBook in Chrome, Safari and Firefox. I don't know what the equivalent of this logic is in every framework that implements Apollo GraphQL, but I imagine there's a similar way to set the poll interval dynamically. |
Here's an implementation (in TypeScript) that seems to be working for me, though I admittedly haven't tested it thoroughly. It polls initially, stops polling when the window loses focus, then on window re-focus will immediately refetch and start polling again. Further, it aims to provide an API that's as simple as possible to use. This is adapted from our codebase which uses GraphQL Code Generator, so I'm not sure if this is precisely what the pure Apollo usage would look like. Usageconst myQueryResult = useQuery(...); // Don't provide pollInterval here.
useQueryPollingWhileWindowFocused({ pollInterval: 10_000, ...myQueryResult }); ImplementationFor
|
+1. Coming from function usePageVisibility() {
const [isVisible, setIsVisible] = useState(getIsDocumentVisible());
const onVisibilityChange = () => setIsVisible(getIsDocumentVisible());
useEffect(() => {
const visibilityChange = getBrowserVisibilityProp();
document.addEventListener(visibilityChange, onVisibilityChange, false);
return () => {
document.removeEventListener(visibilityChange, onVisibilityChange);
};
});
return isVisible;
}
const isVisible = usePageVisibility();
const {
data,
loading,
startPolling,
stopPolling,
} = useQuery(q, {
variables: {
account,
},
pollInterval: 5000,
});
useEffect(() => {
if (!isVisible) {
stopPolling();
} else {
startPolling(pollInterval);
}
}, [isVisible, stopPolling, startPolling]); A simple |
Big +1 to this feature! This would be extremely helpful for us to refresh app state when a user returns to the window after inactivity. |
I don't want to be that guy but... this seems that kind of a problem that is going to be forgotten for centuries. Are the workarounds working as you expect guys? |
+1 for this feature. Any plans for this to be introduced in the future? |
@LasaleFamine it's not forgotten... 😉 It still has a lot of interest which is great to see. |
👋 If anyone in the community has interest in helping to deliver this feature, we've created an issue to work from our Apollo Client repository. |
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.
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.
Is this feature merged by any chance ? |
I ended up creating a custom hook that uses the browser's focus event and refetches the query whenever the window gains focus. It has a default 15 second invalidation duration but it can be customized per-query. So far it has worked great for our use case. Note: this hook also rewrites the import type { OperationVariables, QueryHookOptions, QueryResult, TypedDocumentNode } from '@apollo/client';
import { useQuery } from '@apollo/client';
import type { DocumentNode } from 'graphql';
import { useCallback, useRef, useEffect } from 'react';
const DEFAULT_INVALIDATE_AFTER = 15_000;
/**
* A wrapper around useQuery that will show stale data while loading.
*
* @param query - The GraphQL query to run
* @param options - The query options, forwarded to useQuery
* @returns The result of the query, with loading set to false even for stale data
*/
export function useData<TData, TVariables extends OperationVariables>(
query: TypedDocumentNode<TData, TVariables> | DocumentNode,
options?: QueryHookOptions<TData, TVariables> & {
invalidateAfter?: number;
}
): QueryResult<TData, TVariables> {
const { invalidateAfter = DEFAULT_INVALIDATE_AFTER } = options ?? {};
const result = useQuery(query, options);
const lastRefetchAt = useRef(Date.now());
if (result.loading) {
const data = result.client.readQuery({
query: query,
variables: result.variables,
});
if (data) {
// Rewrite loading to false to show stale but fast data
result.loading = false;
}
}
// This callback re-fetches the current query if it has not been re-fetched in the last N seconds.
// We pass it to useOnFocus to re-fetch the query when the app regains focus.
const onFocus = useCallback(() => {
const diff = Date.now() - lastRefetchAt.current;
if (diff > invalidateAfter) {
lastRefetchAt.current = Date.now();
result.refetch();
}
}, [result, invalidateAfter]);
useOnFocus({
onFocus: onFocus,
});
return result;
}
function useOnFocus({ onFocus }: { onFocus: () => void }) {
useEffect(() => {
const handleFocus = () => {
onFocus();
};
window.addEventListener('focus', handleFocus);
return () => {
window.removeEventListener('focus', handleFocus);
};
}, [onFocus]);
} |
Hey all 👋 This looks to be a popular request given the number of reactions and responses in this request. Apologies for the lack of response from the Apollo team on this issue. In an effort to move this forward, I wanted to bring up a point of discussion that I think might be an important distinction for this feature. I see this feature has been referred to as "focus refetching", but looking at various solutions and original issue description, I'd opt to name this something along the lines of "focus polling" instead. Focus refetching, to me, implies that a refetch would occur for a query when the window is focused, not that polling would resume. Focus refetching in this way I think still makes sense for the client in addition to focus polling. @aditya-kumawat has expressed interest in moving this feature forward so be on the lookout for updates on this feature! Depending on timing, we may try and target this for 3.10.0. Thanks! |
Hey all 👋 This feature was just released in As such, I'm going to go ahead and close this out as completed as I believe it satisfies the original ask in this request. Big thanks to @aditya-kumawat for the implementation! |
Hi @jerelmiller I feel like this option only satisfies 1/2 of the initial request. There are two requirements described above:
I don't think Apollo natively supports #2 yet outside of a custom implementation by the developer. For reference: https://tanstack.com/query/v4/docs/framework/react/guides/window-focus-refetching |
@tylerzey that is fair. Reading through the above, many of the suggestions and code solutions were centered around polling, hence why this seemed to satisfy that request, but #2 makes sense on its own outside of polling. I'd prefer to track it separately though as I feel this thread has grown quite large and might be difficult to parse through (hence why I originally closed this, thinking the request was fully satisfied). Would you be willing to open a new feature request specific to focus refetching? No worries if not. I'd be happy to do it otherwise (it just provides better signal when a non-maintainer opens the request 😆) |
Currently, Apollo Client's
pollInterval
refetches every n milliseconds, regardless of whether the user is actively using the page or not, which isn't optimized. Rising libraries such as SWR or React Query support focus refetching, meaning that the client will not poll if the user has switched to a different tab or window, and it will immediately fetch again if the user comes back to the tab. This saves a lot of wasted requests, while maintaining a great UX.It would be nice to see such feature implemented in Apollo Client as well.
This is how these 2 libraries implement the focus:
https://github.com/vercel/swr/search?q=isDocumentVisible&unscoped_q=isDocumentVisible
https://github.com/tannerlinsley/react-query/search?q=isDocumentVisible&unscoped_q=isDocumentVisible
The text was updated successfully, but these errors were encountered: