vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.04k stars 27k forks source link

Loading with parallel routes only works on root #72850

Open bananashell opened 1 day ago

bananashell commented 1 day ago

Link to the code that reproduces this issue

https://github.com/bananashell/nextjs-parallel-route-loading-issue

To Reproduce

  1. next dev
  2. hard reload localhost:3000 (loading of header is done as expected)
  3. hard reload localhost:3000/a
  4. loading of header is skipped and entier page results in being sync

Current vs. Expected behavior

If a loading.tsx is added to the root of a parallel route it only uses that suspense boundary on the root level.

Give this tree

/ (root)
    @header
        page.tsx
        default.tsx
        loading.tsx
    /a
        page.tsx
        loading.tsx
    /b
        page.tsx
        loading.tsx

The only solution I've found for this is to manually add a Suspense boundary to default.tsx

// @header/default.tsx
import HeaderSlot from "./page";
import { Suspense } from "react";
import Loading from "./loading";

export default function DefaultSlot() {
    return (
        <Suspense fallback={<Loading />}>
            <HeaderSlot />
        </Suspense>
    );
}

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: unknown
  Available memory (MB): 36864
  Available CPU cores: 14
Binaries:
  Node: 22.6.0
  npm: N/A
  Yarn: 1.22.22
  pnpm: N/A
Relevant Packages:
  next: 15.0.3 // Latest available version is detected (15.0.3).
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: N/A
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Parallel & Intercepting Routes

Which stage(s) are affected? (Select all that apply)

next dev (local), next start (local)

Additional context

No response

bananashell commented 1 day ago

It might be that a clarification in the documentation is all that is needed.

Either that default.tsx doesn't cause a Suspense boundary with loading.tsx or that async default.tsx are discouraged and that you should only do @header/[...path]/page.tsx + @header/[...path]/loading.tsx when you by default want to render the same content on all sub routes.

Kinda like the mental model

if(validationOk){
  return OK()
}

return Error()

vs

if(!validationOk){
  return Error()
}

return OK()