react-doctor/tanstack-start-loader-parallel-fetch
Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to avoid request waterfalls in route loaders
- Category: Performance
- Severity: warn
- Source:
oxlint-plugin-react-doctor - Framework: tanstack-start
- Enabled when: framework=tanstack-start and capabilities=tanstack-start
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires when a route's loader function body contains 2 or more top-level await statements, counted across VariableDeclaration, ExpressionStatement, ReturnStatement, and for-await-of forms. Awaits nested inside if/try/loops do not count. False positive: the second await genuinely depends on data resolved by the first, in which case sequencing is required.
Fix prompt
Use this once validation confirms the diagnostic is real.
Wrap independent fetches in Promise.all: const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]). Keep awaits sequential only when the next call's arguments depend on the prior result. For multi-step graphs, consider batching upstream rather than chaining in the loader. See https://tanstack.com/router/latest/docs/framework/react/guide/data-loading
Related rules
More Performance rules from the rules reference:
react-doctor/advanced-event-handler-refs: Store the handler in a ref and have the listener read `handlerRef.current()` — the subscription stays put while the latest handler is always calledreact-doctor/async-await-in-loop: Collect the items and use `await Promise.all(items.map(...))` to run independent operations concurrentlyreact-doctor/async-defer-await: Move the `await` after the synchronous early-return guard so the skip path stays fastreact-doctor/async-parallel: Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrentlyreact-doctor/client-passive-event-listeners: Add `{ passive: true }` as the third argument: `addEventListener('scroll', handler, { passive: true })`. Only do this if the handler does NOT call `event.preventDefault()` — passive listeners silently ignore `preventDefault()`, which breaks features like pull-to-refresh suppression, custom gestures, and nested-scroll containment.