Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

RFC: Component-level Visibility-based Query Management #9934

Unanswered
minseong0324 asked this question in Ideas
Discussion options

RFC: Component-level Visibility-based Query Management

Implementation

Here


Problem

refetchOnWindowFocus works well, but it's window-scoped.

In practice, I often need finer control:

// MFE with multiple QueryClients
<QueryClientProvider client={clientA}>
 <SectionA />
</QueryClientProvider>
<QueryClientProvider client={clientB}>
 <SectionB />
</QueryClientProvider>

// Only the active tab should refresh
<Tabs>
 <TabPanel id="analytics"><AnalyticsPanel /></TabPanel>
 <TabPanel id="users"><UsersPanel /></TabPanel>
</Tabs>
// Widgets below the fold shouldn't fetch until scrolled into view
<Dashboard>
 <RevenueWidget /> {/* visible */}
 <OrdersWidget /> {/* not visible yet */}
</Dashboard>

Doing this manually means setting up IntersectionObserver, tracking state, coordinating invalidation... it adds up.


Proposal

Visibility-based query management at the component level.

Hook

function Widget() {
 const { ref, isFocused } = useComponentFocus({
 componentKey: 'revenue',
 invalidateOnFocus: true,
 })
 const { data } = useQuery({ queryKey: ['revenue'], queryFn: fetchRevenue })
 return <div ref={ref}>{data}</div>
}
function Dashboard() {
 const { registerComponent, focusGroup, blurGroup } = useComponentFocusGroup({
 groupKey: 'dashboard',
 componentKeys: ['a', 'b'],
 })
 return (
 <>
 <button onClick={focusGroup}>Refresh All</button>
 <div ref={registerComponent('a')}><WidgetA /></div>
 <div ref={registerComponent('b')}><WidgetB /></div>
 </>
 )
}

Component

<ComponentFocus componentKey="revenue" invalidateOnFocus>
 <RevenueChart />
</ComponentFocus>
<ComponentFocusGroup groupKey="dashboard" componentKeys={['a', 'b']}>
 {({ registerComponent, focusGroup }) => (
 <>
 <button onClick={focusGroup}>Refresh All</button>
 <div ref={registerComponent('a')}><WidgetA /></div>
 <div ref={registerComponent('b')}><WidgetB /></div>
 </>
 )}
</ComponentFocusGroup>

How it works

  • Uses IntersectionObserver to detect visibility
  • Invalidates/refetches queries when component enters viewport
  • Respects tab switching and window blur
  • Works with multiple QueryClient instances

Use cases

Third-party Widget Integration

<QueryClientProvider client={appClient}>
 <App />
</QueryClientProvider>
<QueryClientProvider client={widgetClient}>
 <AnalyticsWidget /> {/* loads data only when scrolled into view */}
</QueryClientProvider>

Isolated Feature Modules

<QueryClientProvider client={paymentClient}>
 <PaymentSection /> {/* separate cache policy for sensitive data */}
</QueryClientProvider>
<QueryClientProvider client={mainClient}>
 <ContentSection />
</QueryClientProvider>

MFE Portal

<QueryClientProvider client={teamAClient}>
 <Header />
</QueryClientProvider>
<QueryClientProvider client={teamBClient}>
 <Sidebar />
</QueryClientProvider>
<QueryClientProvider client={teamCClient}>
 <MainContent />
</QueryClientProvider>

On window focus, only visible sections refetch — each with their own QueryClient.


Open questions

  1. Useful enough to add as experimental?
  2. Separate package or integrated into react-query?

Thoughts?

You must be logged in to vote

Replies: 2 comments

Comment options

correct me if I’m wrong but I don’t think this has a lot to do with react-query - it’s more about visibility management and then one consumer of that would be refetching with react-query?

Probably a better design for this lib would be to just expose a function that will be called whenever something becomes visible, and then users can do with that information what they want instead of having query specific options like, invalidateOnFocus, refetchOnFocus, resetOnFocus etc.

I don’t think this has a place in the query repo but it sounds like a nice package you could publish.

You must be logged in to vote
0 replies
Comment options

@TkDodo Thanks for the feedback. Visibility management is a concern, but not the only one.

One thing I'm thinking about though: in setups where modules have separate QueryClient instances, each module usually has its own QueryClientProvider.

If we only expose an onFocusChange callback, each module would need to access its own QueryClient (via useQueryClient()), define its invalidation logic, and pass that callback up to the parent. That means either the parent needs to know about each module's query structure, or modules need to expose their handlers — which feels like it increases coupling.

What do you think?

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /