vercel / next.js

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

Duplicate/Double rendering in App Directory #47145

Open cyrilcabo opened 1 year ago

cyrilcabo commented 1 year ago

Verify canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #30-Ubuntu SMP Mon Apr 20 16:58:30 UTC 2020
    Binaries:
      Node: 18.12.0
      npm: 8.19.2
      Yarn: 1.22.18
      pnpm: N/A
    Relevant packages:
      next: 13.2.5-canary.3
      eslint-config-next: 13.2.4
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue

https://github.com/cyrilcabo/nextjs-app-duplicate-rendering

To Reproduce

  1. Run yarn build on the project

  2. During build, you'll notice that for each page that's being built, two console.logs always run:

    yarn run v1.22.18 $ next build warn - You have enabled experimental feature (appDir) in next.config.js. warn - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. info - Thank you for testing appDir please leave your feedback at https://nextjs.link/app-feedback info - Compiled successfully info - Creating an optimized production build .info - Linting and checkin info - Linting and checking validity of types ..Pages directory cannot be found at /mnt/Misc/home/cyrilcabo/Desktop/TO_DELETE/test-app/pages or /mnt/Misc/home/cyrilcabo/Desktop/TO_DELETE/test-app/src/pages. If using a custom path, please configure with the no-html-link-for-pages rule in your eslint config file. info - Linting and checking validity of types
    info - Collecting page data
    info - Creating an optimized production build ... BODY: How many times I render Static Page BODY: How many times I render slug-1 HEAD: How many times I render Static Page HEAD: How many times I render slug-1 info - Creating an optimized production build . HEAD: How many times I render Static Page [== ] info - Generating static pages (3/8) BODY: How many times I render Static Page BODY: How many times I render slug-2 HEAD: How many times I render slug-2 HEAD: How many times I render slug-2 BODY: How many times I render slug-2 HEAD: How many times I render slug-1 info - Creating an optimized production build .. BODY: How many times I render slug-1 info - Generating static pages (8/8) info - Creating an optimized production build .info - Finalizing page opt info - Finalizing page optimization

  3. After building, you can try running yarn start.

  4. Visit any of the pages:

    • http://localhost:3000/test-path/slug-3
    • http://localhost:3000/test-path/slug-4
  5. On the terminal, you'll see duplicate console.logs:

    yarn run v1.22.18 $ next start ready - started server on 0.0.0.0:3000, url: http://localhost:3000 warn - You have enabled experimental feature (appDir) in next.config.js. warn - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. info - Thank you for testing appDir please leave your feedback at https://nextjs.link/app-feedback BODY: How many times I render slug-3 HEAD: How many times I render slug-3 HEAD: How many times I render slug-3 BODY: How many times I render slug-3 BODY: How many times I render slug-4 HEAD: How many times I render slug-4 HEAD: How many times I render slug-4 BODY: How many times I render slug-4

Describe the Bug

As you can see, there are multiple renders from the body or page, and this causes the page to call a third party API multiple times. We've had instances where we exceeded API limits because of this. This https://beta.nextjs.org/docs/data-fetching/caching#preload-pattern-with-cache didn't help either as the renders happen a few seconds after the other.

yarn run v1.22.18 $ next start ready - started server on 0.0.0.0:3000, url: http://localhost:3000 warn - You have enabled experimental feature (appDir) in next.config.js. warn - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. info - Thank you for testing appDir please leave your feedback at https://nextjs.link/app-feedback BODY: How many times I render slug-3 HEAD: How many times I render slug-3 HEAD: How many times I render slug-3 BODY: How many times I render slug-3 BODY: How many times I render slug-4 HEAD: How many times I render slug-4 HEAD: How many times I render slug-4 BODY: How many times I render slug-4

Expected Behavior

There should only be one render per each page:

yarn run v1.22.18 $ next start ready - started server on 0.0.0.0:3000, url: http://localhost:3000 warn - You have enabled experimental feature (appDir) in next.config.js. warn - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk. info - Thank you for testing appDir please leave your feedback at https://nextjs.link/app-feedback BODY: How many times I render slug-3 HEAD: How many times I render slug-3 HEAD: How many times I render slug-4 BODY: How many times I render slug-4

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

next start

skworden commented 1 year ago

I ran into a similar issue and I just discovered that React 18 is testing conditional mounting and reusable state.

If strict mode is enabled, which is the default setting in Next.js, React automatically performs a double rendering of components. This double rendering is a deliberate approach to help developers adapt to and prepare for the integration of this new features.

In short we need to build our components and pages to be re-rendered multiple times and can no longer depend on things like an empty dependency array.

React 18 docs on the topic This video explains it in detail and how to properly clean up / detect mounts - https://youtu.be/MXSuOR2yRvQ?t=559

magnnus commented 5 months ago

I had ran into the same issue in Production Mode (next start).

And found a discussion #43158.

When i try to delete generateStaticParams, the page.tsx render once!But the Cache-Control changes to private, no-cache, no-store, max-age=0, must-revalidate

See also #52934

once for html, once for rsc