I have a CSR app with the following route definitions:
const router = createBrowserRouter([
{
path: '/app/',
element: <NavBar />,
loader: navBarLoader,
children: [
{
path: 'placement-selection',
Component: PlacementSelection,
loader: placementSelectionLoader,
children: [
{
path: 'options',
Component: PlacementSelectionOptions,
loader: placementSelectionOptionsLoader,
children: [
{
path: 'summary',
Component: PlacementSelectionOptionsSummary,
loader: placementSelectionOptionsSummaryLoader,
},
],
},
],
},
],
},
]);
And the following loaders:
export async function navBarLoader() {
console.log('called navBarLoader')
return await new Promise((res, rej) => {
setTimeout(() => res('response'), 2000)
})
}
export async function placementSelectionLoader() {
console.log('called placementSelectionLoader')
return await new Promise((res, rej) => {
setTimeout(() => res('response'), 2000)
})
}
export async function placementSelectionOptionsLoader() {
console.log('called placementSelectionOptionsLoader')
return await new Promise((res, rej) => {
setTimeout(() => res('response'), 2000)
})
}
export async function placementSelectionOptionsSummaryLoader() {
console.log('called placementSelectionOptionsSummaryLoader')
return new Promise((res, rej) => {
setTimeout(() => res('response'), 10000)
})
}
This is how PlacementSelectionOptionsSummary
is using the loader data:
import { Suspense } from 'react';
import './styles.css';
import { Await } from 'react-router';
export default function PlacementSelectionOptionsSummary({ loaderData }) {
return (
<>
<Suspense fallback={<div>Loading...</div>}>
<Await resolve={loaderData}>
{value => <h3>Non critical value: {value}</h3>}
</Await>
</Suspense>
<div className="main-container" style={{ width: '30%' }}>
<div className="container" style={{ height: '500px' }}>
<div className="card" style={{ backgroundColor: 'blue' }}>
<span className="description">
{' '}
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean
tempor ante ligula, id aliquet ligula laoreet id. In aliquam
hendrerit mauris, at sagittis tortor efficitur non. Proin egestas
facilisis augue. Sed aliquet maximus tempus. Nullam ornare
efficitur blandit. Sed eu mattis tortor. Lorem ipsum dolor sit
amet, consectetur adipiscing elit. Aenean tempor ante ligula, id
aliquet ligula laoreet id. In aliquam hendrerit mauris, at
sagittis tortor efficitur non. Proin egestas facilisis augue. Sed
aliquet maximus tempus. Nullam ornare efficitur blandit. Sed eu
mattis tortor',
</span>
</div>
</div>
</div>
</>
);
}
As you can see, placementSelectionOptionsSummaryLoader
takes 10 seconds, where all others take 2 seconds.
Based on what’s mentioned here: https://reactrouter.com/how-to/suspense, I figured that all I need to do was to just return the Promise directly, which I am doing for this loader.
Still, the UI for the route /app/placement-selection/options/summary
waits for all of these loaders to “finish” before the UI renders.
How can I get most of the UI to render, and then only have PlacementSelectionOptionsSummary
render a fallback until it’s slow-10-seconds-loader finishes?