Replies: 5 comments 8 replies
-
This wouldn't work for a server render. You can transfer a non-serializable object from the loader function to your component, primarily for this reason. A loader is meant to provide a snapshot of data, not an active connection or more complex object. This is obviously to serve the upstream Remix library, but works the same for anyone doing server rendering. |
Beta Was this translation helpful? Give feedback.
-
Why couldn't you use a // route.jsx
let statefulSubscriptionThing;
export async function loader() {
if (!statefulSubcriptionThing) {
statefulSubcriptionThing = createStatefulThing();
}
let data = await statefulSubscriptionThing.getData();
return { data );
}
export function Component() {
let data = useLoaderData();
React.useEffect(() => () => {
if (statefulSubcriptionThing) {
statefulSubcriptionThing.destroy();
}
}, []);
return <div>{data}</div>
} |
Beta Was this translation helpful? Give feedback.
-
I also wish there was a way to do cleanup. I'm using RTK Query and when I fetch data in a Too bad there seem to be no support for this yet. |
Beta Was this translation helpful? Give feedback.
-
Proposal for adding a way to add cleanup logicAdd a property to the argument for the loader which allows cleanup. Example codeconst loaderFunc = async ({ request, params, onUnload }) => {
// fetch and add a subscription
const removeStateFullStuffCallback = await doSomeStateFullStuff();
// add cleanup function which is called when navigating away
onUnload(() => { removeStateFullStuffCallback(); });
// return some data
return {};
} A concrete example for RTK QueryRTK Query adds subscriptions for data. Data is held in the cache until all subscriptions for it are removed. If for example only one page needs certain data it should be cleaned up when the page is left. const loaderFunc = async ({ request, params, onUnload }) => {
// fetch and add a subscription
const queryResult = dispatch(api.endpoints.getFancyStuff.initiate(undefined, { forceRefetch: true }));
// remove subscription when navigating away
onUnload(() => { queryResult.unsubscribe(); });
// await the query to delay the navigation till data is loaded
await queryResult;
// return no data since components can access data via useQueryState()
return null;
} Open questions
Current workaroundSince this is not possible yet the current workaround is to use const loaderFunc = async () => {
// fetch and add a subscription
const queryResult = dispatch(api.endpoints.getFancyStuff.initiate({ forceRefetch: true }));
// listen to next route change to remove the subscription when navigating away
// first we will get the current route change, so we use a boolean to fire the callback on the second invocation
let isUnload = false;
const unsubscribeFromRouter = router.subscribe(() => {
if (isUnload) {
console.log("UNLOAD");
queryResult.unsubscribe(); // remove RTK Query subscription
unsubscribeFromRouter(); // stop listening to route changes
}
isUnload = true;
});
// await the query to delay the navigation till data is loaded
await queryResult;
// return no data since components can access data via useQueryState()
return null;
} However, this is not great since it
Other workaroundsUsing
|
Beta Was this translation helpful? Give feedback.
-
Hi there, |
Beta Was this translation helpful? Give feedback.
-
Some frameworks like Convex, Firebase, or Supabase have stateful subscriptions for data loading. It would be great if you could subscribe to an object / topic in the loader and the listen to it in the component. The framework would need to provide hooks to separate subscription and reactivity but this would otherwise work today. The issue is that there is not a clear way to clean up the subscription when the route no longer matches. A cleanup function would allow the app to unsubscribe from the query.
Beta Was this translation helpful? Give feedback.
All reactions