react-router
react-router copied to clipboard
[Bug]: signal never gets aborted upon navigation for non-awaited deferred loader
What version of React Router are you using?
6.9.0
Steps to Reproduce
function fetchA(signal: AbortSignal) {
signal.addEventListener('abort', () => console.log('Fetcher A cancelled'));
return Promise.resolve('a');
}
function fetchB(signal: AbortSignal) {
signal.addEventListener('abort', () => console.log('Fetcher B cancelled'));
return new Promise(() => {});
}
export function loader({request: {signal}}: LoaderFunctionArgs) {
return defer({
a: await fetchA(signal),
b: fetchB(signal)
});
}
Expected Behavior
In the example deferred loader setup above, with some awaited load functions and other non-awaited functions that take a potentially long time to resolve, the abort signal passed to fetchB
should be aborted when navigating away from the page before the loader completes.
Actual Behavior
If the awaited functions have resolved, the signal passed to fetchB
is not aborted upon navigation.
Having a brief look at the code, I think this happens because on line https://github.com/remix-run/react-router/blob/5c03b9c540340d861d50895b443b37fda0a744d0/packages/router/router.ts#L1278 the pendingNavigationController
is cleared with the assumption that the loaders have completed, which isn't necessarily true in the deferred case. Because of that, when the new navigation starts, the signal is never aborted https://github.com/remix-run/react-router/blob/5c03b9c540340d861d50895b443b37fda0a744d0/packages/router/router.ts#L1165
It seems to me that to properly support the deferred use case, pendingNavigationController
should simply not be cleared - the signal would then be aborted upon every navigation, but in most cases there would be no loader functions listening to it any more, so nothing would happen.
I'm currently facing this issue with defer & signal not aborted. Is there a workaround we can implement at least ?
Same here. Any fix?
@ryanflorence sorry for tagging directly, but is there a chance this could at least be triaged? It doesn't seem there's been any activity from the team here since this was posted more than a year ago. Happy to provide more context or a fully reproducible example if needed.
I consider this a fairly serious issue, because if there are expensive loading operations inside the defer
call, they won't get cancelled upon navigating away from the current view.
In an example case where each page starts to load a large dataset, but the user might quickly navigate away to a different page, this will lead to wasting the user's bandwidth on a lot of unnecessary data loading, potentially leading to a degraded experience...
If my diagnosis of the cause of the problem is correct, then the solution suggested in the original post still seems to apply, even though the exact line numbers have changed since.