T
TanStack2y ago
fascinating-indigo

Data Loading with Prefetch and UI skeleton

Currently, upon clicking a link the route is updated in the URL and a loading indicator is displayed until loader is resolved. I just want to show something to user as soon as they click. I think this provides much smoother UX. I would still like to use loader (with prefetch enabled) but show some static text /UI skeleton placeholders in the route page while data is resolved in the background and available in react query. Did any one figure this out yet?
8 Replies
wise-white
wise-white2y ago
Data Loading | TanStack Router Docs
Data loading is a common concern for web applications and is related to routing. When loading a page for your app, it's ideal if all of the page's async requirements are fetched and fulfilled as early as possible, in parallel. The router is the best place to coordinate these async dependencies as it's usually the only place in your app that kno...
fascinating-indigo
fascinating-indigoOP2y ago
I'm already using pending component. It shows a loading icon for entire page until the loader is resolved. I'm actually looking for a way to show the page first with some static data say a tilte: Ex: Contacts and then show loading indicator only for parts of it while loader is resolved.
wise-white
wise-white2y ago
I am not sure if this is what you want, but I would just avoid using a loader, I'd manage it in the component(with tanstack query)
fascinating-indigo
fascinating-indigoOP2y ago
The main reason to use loader is to prefetch the data upon hovering the links.
wise-white
wise-white2y ago
you could use defer, and then handle your data as a promise in the component: https://tanstack.com/router/latest/docs/framework/react/guide/deferred-data-loading
Deferred Data Loading | TanStack Router Docs
TanStack Router is designed to run loaders in parallel and wait for all of them to resolve before rendering the next route. This is great most of the time, but occasionally, you may want to show the user something sooner while the rest of the data loads in the background. Deferred data loading is a pattern that allows the router to render the ...
fascinating-indigo
fascinating-indigoOP2y ago
This also doesnt preload the data.
inland-turquoise
inland-turquoise2y ago
you would need to split up into hierarchical routes. then each route can have its own pending component check the kitchen sink example
fascinating-indigo
fascinating-indigoOP2y ago
I see what you suggesting here. Extract the static data into one more hierarchical route. Preloading doesnt work in this case. I'm trying to find that sweet spot where preloading should just work normally and then show pending component only for the part where loader data is required. I think I got this working.
loader: ({context: {queryClient, queryOpts}}) => {
return queryClient.ensureQueryData(queryOpts)
}
loader: ({context: {queryClient, queryOpts}}) => {
return queryClient.ensureQueryData(queryOpts)
}
Remove the return statement in the loader and the route wont wait until the promise is resolved. In the component, wrap everything that needs query in a Suspense boundary
export default function Page() {
return (
<>
<h1>Page Title</h1>
<Suspense fallback={<LoadingIndicator/>}>
<PageContent/>
</Suspense>
</>
)
}
export default function Page() {
return (
<>
<h1>Page Title</h1>
<Suspense fallback={<LoadingIndicator/>}>
<PageContent/>
</Suspense>
</>
)
}
The route will be loaded immediately with showing Page Title and then a pending indicator will be displayed for the rest of the page until the loader is resolved. Thank you @ferretwithabéret @Manuel Schiller 🙌🏽

Did you find this page helpful?