-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
feat: Add skipPollAttempt
option to control polling refetch behavior
#11397
feat: Add skipPollAttempt
option to control polling refetch behavior
#11397
Conversation
@aditya-kumawat: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/ |
|
Name | Link |
---|---|
🔨 Latest commit | 8e38108 |
🦋 Changeset detectedLatest commit: e452328 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
8e38108
to
e5ee90f
Compare
Hey @aditya-kumawat 👋 Appreciate the contribution here! I'd love to get a couple things from you here regarding this change. We are generally hesitant to expand the footprint of options that can be provided to our APIs so I'd love to dig a bit deeper and discuss what existing limitations there are and how you see this as an improvement on the "status quo".
Given your example using const { startPolling, stopPolling } = useQuery(QUERY, { pollInterval: 5000 })
useEffect(() => {
function handleVisibilityChange() {
if (document.hidden) {
stopPolling()
} else {
startPolling(5000)
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
}, [startPolling, stopPolling]) Changes to const [pollInterval, setPollInterval] = useState(5000)
useQuery(QUERY, { pollInterval })
useEffect(() => {
function handleVisibilityChange() {
setPollInterval(document.hidden ? 0 : 5000)
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
}, []) I know its a tad verbose, but what I'm trying to illustrate here is that this should be possible given the current API. What I'd love to get from you is to more deeply understand what you see as the limitation with the existing tools, what other use cases you can see for this API, and how this option helps avoid those challenges with the existing API. Once again, appreciate the contribution here! |
I see I need to make fresh changes after the rebase. Will do it but unable to run |
@jerelmiller Thanks for quick response. Solution proposed by you works fine for a single query. In my organisation we are using It's not feasible to update each and every instance given the large number. We already have a wrapper created on top of |
@aditya-kumawat that makes sense.
Perhaps I'm just not seeing it, but I don't quite see how your proposed solution here fixes this issue. Or are you specifically referring to the fact that you're trying to avoid writing that To touch a bit more on the goal of this API, are you specifically after focus refetching with this feature as talked about in apollographql/apollo-feature-requests#247, or are you looking for this to be a more generalized API that lets you selectively enable/disable polling based on any condition? |
We created following utility to control things across the codebase. export const generateQueryHook =
<TQuery, TVariables extends OperationVariables = OperationVariables>(
query: DocumentNode,
) =>
(options?: QueryHookOptions<TQuery, TVariables>) =>
useQuery<TQuery, TVariables>(query, options); If I have an option to pass My use-case is limited to apollographql/apollo-feature-requests#247 only for now. I raised a PR for more generalised API expecting something like that might be needed in future. If you don't want to expose, it should be fine if we can add a boolean option just to handle inactivity scenario. |
I love that you've got an abstraction thats been working well for you in your codebase! I always love to see creative ways people use these hooks. Something to keep in mind with this specific feature is that unfortunately most of the Apollo users won't have something like this in their codebase and tend to use
This is useful! I'd propose then that whatever API is added to the client would be a feature specific to this issue rather than a more generalized API. If we approach it this way, we'll have the freedom to make this a more "automatic" thing in the client. I'd also like to separate this particular concept (I'll call it focus polling) from focus refetching. I see the two as slightly different concepts. Focus polling would allow you to only run the poll interval when the window is focused, where focus refetching would allow you to run a If we were to move this feature forward, there are a few things that we'd need to make this work in order to make it a non-breaking change.
Here is a rough idea for what this might look like (terrible name for the option for now, but it gets the idea across) const client = new ApolloClient({
defaultOptions: {
// This should only be available for watchQuery since its the only one that allows polling
watchQuery: {
// Only allow polling when the window is focused. Enables it everywhere. Default is `false`
focusPolling: true
}
}
});
function MyComponent() {
// Override the global focusPolling option for a single query
useQuery(QUERY, { focusPolling: false })
} Given the above, are you still interesting in working on this feature? And if so, would you prefer to work on it in this PR, or open a new, fresh PR? I'd be happy to collaborate with you to help you get it across the finish line. |
@jerelmiller This really helps. I like the solution you proposed and can work on it(unless I get stucked and might need others to pick it up). I will prefer to use the same PR as the discussion might come in handy for others. I can create a new one if you feel otherwise.
I am not sure about how to handle this scenario though. Can you help out with this one? |
@aditya-kumawat this PR should be fine! Feel free to update this one and work on it here. A couple things I'd ask if you could do for us:
Tests are the critical one to us getting this merged as it lets us know you've considered all the cases and makes sure we don't break anything in the future regarding this feature. These things would be super helpful though in the mean time!
You should be able to check whether typeof window !== 'undefined' Assuming you'll be using Oh, and one more thing I just thought of while I'm here. Tanstack Query has the ability to determine which events cause focus, that way you're not limited to whatever the library chose. I'm not asking for an API like this one, but would love for you to think through this a bit and whether we'd need the ability for the user to specify or change the events that would trigger focus so that polling enables/disables appropriately. Hopefully this makes sense! |
@jerelmiller I will make sure of the checklist you mentioned above. I am refraining myself from using What are your thoughs on this? |
shouldPollingBeEnabled
option for useQuery
focusPolling
option to disable polling if tab is inactive
This may very well be the right solution! I'll leave it up to you what seems the most appropriate here and give you a chance to play around with it a bit to see what works the best. Something to consider here is whether you'd like the fetch to occur the moment the window is focused, or whether it just re-enables itself on the next tick of the interval (which might be several seconds after focus, depending on the poll interval). Again, this might be totally appropriate here! Just wanted to make sure you're thinking of this as well so that we can explain the decision/behavior here in case we get questions about how this feature works. |
focusPolling
option to disable polling if tab is inactivefocusPolling
option to disable refetching if tab is inactive
846a741
to
edbbb39
Compare
@aditya-kumawat FYI just realized you're using a fork of the library that is several years old at this point. Some of those methods you're touching don't exist anymore. To save yourself some time, I'd recommend ensuring your fork is up-to-date with the latest changes in Just wanted you to be aware of this! |
69233a3
to
b920b5a
Compare
@jerelmiller Thanks for pointing this out. Earlier I made the changes correctly but after rebase with PTAL at the code changes for initial review. Will add tests and mark this PR ready for review if it looks good. |
b920b5a
to
a9b882a
Compare
Initial glance looks good, but I'd prefer to do a thorough review after you've had a chance to write tests in case you find edge cases that require you to change the logic needed to make this work correctly. |
49968ff
to
d1ea6fe
Compare
@jerelmiller Done adding the tests as well but some unrelated tests are failing. I think so as those tests are failing locally on |
c4fd486
to
17f4ac9
Compare
@jerelmiller @Meschreiber Thanks for the review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc comment LGTM! Thanks @aditya-kumawat !
Hey @aditya-kumawat 👋 We'll be discussing the name of this option in our next team meeting and will get back to you assuming we reach consensus on a final naming decision here. I'm hopeful to have another review to you tomorrow! |
@jerelmiller Sounds good to me. Thanks for the update. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @aditya-kumawat 👋
This should be my last review needed. I've talked with the team and we decided we like the name skipPollAttempt
for this option. Once you're able to get this PR updated with that name, I'll get this PR approved and into the release branch. We should be able to get this into the next alpha release.
Thanks so much again for the contribution! Excited to get this one in there!
17f4ac9
to
7e9f466
Compare
@jerelmiller Suggestions looks good. Done with the changes. |
shouldRefetchOnPolling
option to control polling refetch behaviorskipPollAttempt
option to control polling refetch behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
@aditya-kumawat don't worry about this at all! We also went back and forth on our end a bit. I'm very appreciative for receiving my feedback and iterating on this. Hope to see more contributions for you in the future! I'll get this merged to our next release branch. Look out for this in the next minor release 3.9.0! We'll also plan to get this out in the next prerelease alpha version so you can try it out in your own apps before 3.9.0 ships. |
) Co-authored-by: Aditya Kumawat <[email protected]>
) Co-authored-by: Aditya Kumawat <[email protected]>
Summary
This adds
skipPollAttempt
optional option to skip refetching if it returnstrue
and works as usual if not set or if it returnsfalse
.This will solve the frequent use-case of disabling polling when the window is inactive(Feature request #247).
Details about the implementation:
Took inspiration from idea proposed here.
Evidences
pollInterval: 1000
Kapture.2023-11-30.at.04.37.52.mp4
pollInterval: 1000, skipPollAttempt: () => document.hidden
Kapture.2023-11-30.at.04.39.50.mp4
skipPollAttempt: () => document.hidden
withstartPolling
andstopPolling
Kapture.2023-11-30.at.04.42.44.mp4
Global
skipPollAttempt: () => document.hidden
Kapture.2023-11-30.at.04.46.11.mp4
Checklist: