vercel / next.js

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

next/dynamic renders loading state when React re-renders quickly client-side #64687

Closed snehakhobragade90 closed 1 month ago

snehakhobragade90 commented 1 month ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/jolly-fog-h86q9z

To Reproduce

  1. Refresh the page preview
  2. As the page loads - you'll observe the dynamic code-split component renders the server response, then flashes the loading state before loading the content

Code Working details:

  1. ClientWrapper component imports a next/dynamic code-split DynamicHeader component
  2. ClientWrapper uses client hooks like useEffect which leads react to render client side

page.tsx

import ClientWrapper from "./ClientWrapper";

export default function Home() {
  return <ClientWrapper />;
}

dynamicHeader.tsx

const DynamicImportComponent = () => {
  return <div>This is the code split dynamically imported component</div>;
};

export default DynamicImportComponent;

ClientWrapper

"use client";
import { useState, useEffect } from "react";
import dynamic from "next/dynamic";

const DynamicHeader = dynamic(() => import("./dynamicHeader"), {
  loading: () => <p>Loading...</p>,
});

const ClientWrapper = () => {
  const [someState, setsomeState] = useState("foo");

  useEffect(() => {
    setsomeState("bar");
  });

  return (
    <div>
      The state is {someState}
      <DynamicHeader />
    </div>
  );
};

export default ClientWrapper;

Current vs. Expected behavior

I would expect that the loading state of the dynamically imported component is not rendered. It renders the server response, then flashes the loading state before rendering the client side rendered content. There should be no flashing of the loading state which harms the application's CLS. Hypothesis why this is happening there is a race condition where the react is rendering and mounting before the code split chunks are loaded. Adding a setTimeout with an arbitrary delay to the react rendering effectively resolves the bug.

Provide environment information

Binaries:
  Node: v20.11.1
  npm: 10.2.4
  Yarn: 4.0.0
  pnpm: N/A
Relevant Packages:
  next: 14.0.4
  eslint-config-next: 14.0.1
  react: ^18
  react-dom: 18.2.0
  typescript: 5.3.2
Next.js Config:
  output: N/A

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

Performance

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

next dev (local), next build (local), next start (local), Other (Deployed)

Additional context

This bug significantly impacts our application's Cumulative Layout Shift metric, thereby detrimentally affecting our SEO performance. It posing a roadblock for us in migrating more URLs to route through the Next app.

Adding of videos from the sandbox and our stripped down app for reference:

https://github.com/vercel/next.js/assets/31524521/0f857076-23fc-4c63-97d0-910f31597c04

huozhi commented 1 month ago

Close as duplicate of #64060, let's track there

github-actions[bot] commented 4 weeks ago

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.