Add tracking of loader/action lifecycles for subscription management, etc #11809
melnikov-s
started this conversation in
Proposals
Replies: 1 comment 1 reply
-
You can already manage subscriptions with a loader by using an event stream response, Remix (which is based on RR so it should be the same) can use the EventSource API to subscribe to a loader that returns an event stream. I imagine a similar thing can be done with plain RR, if you return a stream from a RR loader, actually it should probably be simpler since you can return the stream from the UI loader directly. |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Proposing to add an ability to track the lifecycle of a loader and/or action. This can enable subscription management amongst other things where you'd need to associate state to a loader/action and be able to clean up that state when the loader/action is no longer "active".
I'll use a query subscription management as an example of a real world problem, where we'd need lifecycle tracking in order to solve for.
TL;DR:
To effectively manage subscriptions on loaders, we need to determine:
Background
For illustration, we will use Apollo Client and
watchQuery
subscriptions but in theory this should be applicable to any kind of subscriptionApollo Client is a GraphQL client with a built-in reactive cache. It allows you to use
useQuery
hooks to execute queries with different fetch policies. These fetch policies dictate the data source for the query, either from its global reactive cache or over the network. The default fetch policy reads from the cache, but there are situations where a network fetch is preferred. Other scenarios may require a stale-while-revalidate approach, fetching initial data from the cache, rendering it immediately, and then revalidating over the network to update with the latest data later. Because the cache is global and reactive, mutations that modify the cache should trigger re-renders in components that useuseQuery
to ensure they display the latest data.The
useQuery
hook sets up a subscription when the component mounts, reads the fetch policy, and makes a network request if necessary. Upon re-render or update, it reads from the last result regardless of the fetch policy. If a mutation affects the global state read byuseQuery
, the hook forces a re-render with the latest data. When the component unmounts, the subscription is unsubscribed.The Problem
The challenge with
useQuery
is that it fetches data as you render, while client-side loaders allow for pre-fetching queries. Without the lifecycle concept present in React withuseQuery
, we lose the ability to manage subscriptions. Consequently, we cannot support fetch-while-revalidate fetch policies, updates to mutations (outside of an action), or network-only fetch policies without over-fetching during unrelated loader revalidations.To support this functionality, we need a way to track the lifecycle of a loader similarly to how we track the lifecycle of a component. Additionally, we should have the option to revalidate a single loader or fetcher specifically.
Here’s a playground with
useQuery
that have been migrated to loaders.useQuery - https://stackblitz.com/edit/getting-started-with-graphql-react-i1bqn1
useLoaderData - https://stackblitz.com/edit/getting-started-with-graphql-react-nnxels
Notice that with
useQuery
we only make a single request when changing search params whileuseLoaderData
is forced to recall each query on every revalidation if we wish to keep the same network behavior.Proposal
To track subscriptions across loaders, we need to:
dataStrategy
API provides a suitable vector for introducing this functionality.router.revalidate
but since we only need to revalidate the specific fetcher/loader that wasupdated, we can add an optional parameter to
router.revalidate
to only revalidate specific fetchers/loaders.We can now use it in the following way to handle our subscriptions:
With these additional APIs, React Router will expose all that is needed to manage subscriptions tied to loaders, not just specifically for Apollo Client but theoretically for any kind of subscription previously managed with React hooks.
Beta Was this translation helpful? Give feedback.
All reactions