Skip to content

useFetchers breaking on deferred routes: parallel optimistic rendering not possible with Suspense/Await #14768

@leon-compelling

Description

@leon-compelling

Reproduction

https://github.com/leon-compelling/useFetchers-bug-report/blob/main/app/routes/home.tsx

-> npm run dev or copy file content into an existing react-router project on an empty route and try the different combinations mentioned in the first comment block
-> watch: Loom Recording Of Reproduction

System Info

System:
    OS: macOS 26.2
    CPU: (12) arm64 Apple M4 Pro
    Memory: 155.34 MB / 24.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.14.0 - /Users/leon/.nvm/versions/node/v22.14.0/bin/node
    npm: 11.2.0 - /Users/leon/.nvm/versions/node/v22.14.0/bin/npm
  Browsers:
    Brave Browser: 144.1.86.146
    Chrome: 144.0.7559.110
    Firefox: 147.0.2
    Safari: 26.2
  npmPackages:
    @react-router/dev: 7.12.0 => 7.12.0 
    @react-router/node: 7.12.0 => 7.12.0 
    @react-router/serve: 7.12.0 => 7.12.0 
    react-router: 7.12.0 => 7.12.0 
    vite: ^7.1.7 => 7.3.1

Used Package Manager

npm

Expected Behavior

On routes that use Suspense/Await, multiple useFetcher submissions in quick succession should behave the same as on a blocking route:

  • Each fetcher appears in useFetchers() and progresses through submitting → loading → idle independently.

  • Several fetchers can be inflight at once (e.g. 1–5 overlapping), so the app can render parallel optimistic UI for fast successive user actions (e.g. multiple reorders, un/hides and resizes of columns in a short time).

-> useFetchers() should support multiple concurrent fetchers on deferred routes, just like on blocking routes.

Actual Behavior

On routes that uses deferred data with Suspense/Await:

  • Only one fetcher is effectively inflight.
    • With no action delay: only the first submission shows up in useFetchers() and enters loading; later submissions don’t appear or suddenly go idle / vanish.

    • With an action delay (e.g. 2s): all submissions may show submitting, but only the first ever enters loading; the rest then go idle / vanish.

-> Fast succession interactions are broken: users can’t trigger multiple fetchers in parallel, so parallel optimistic rendering is not possible on deferred routes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions