uikit icon indicating copy to clipboard operation
uikit copied to clipboard

First layout not working on Next.js 14.2.23 - react-dom.development.js:17497 Uncaught Error: Element type

Open LrLamonier opened this issue 10 months ago • 4 comments

My project uses libraries that are not ready for React 19, therefore I am using React 18, Next.js v. 14.2.23, React Three Fiber 8.17.10, and React Three uikit 0.8.4.

When trying to reproduce the first layout example

<Suspense fallback={null}>
    <Canvas
        style={{
          position: "fixed",
          width: "100%",
          height: "100vh",
          top: 0,
          left: 0,
        }}
        gl={{ localClippingEnabled: true }}
    >
        <Root sizeX={2} sizeY={1} flexDirection="row">
            <Container flexGrow={1} backgroundColor="red" />
        </Root>
    </Canvas>
</Suspense>

I get the following error:

Image

The component is a client component with "use client";.

The problem still occurs in a brand new Next project.

What am I doing wrong?

LrLamonier avatar Feb 24 '25 02:02 LrLamonier

Can you check whether its related to uikit or r3f in general by removing the uikit elements and just adding a simple ?

bbohlender avatar Feb 24 '25 09:02 bbohlender

It is uikit related. The tests I did:

  1. Just the canvas - no error
  2. Canvas with a basic object (mesh, box geometry, basic material) - no error
  3. Canvas with an imported gltf model - no error
  4. Canvas with only a <Root /> component - error
  5. The snippet above - error

The crazy thing is that the page actually displays the components correctly, but there is the uncaught error.

Next.js sometimes throws hydration warnings that, in this context, are not a problem since I am actively doing everything on the client. But they’re just warnings. This is an actual error though.

I tried putting it inside its own <Suspense /> boundary. No success.

I tried rendering it conditionally by having an isActive state like so:

const [isActive, setIsActive] = useState(false);

return (
    <Canvas onPointerDown={() => setIsActive(true)}>
        {isActive ?
            <Root>
                …
            </Root>
         : null}
        </Root>
    </Canvas>
)

But it also threw the error even before the component was rendered. When clicking the canvas the content shows up properly.

LrLamonier avatar Feb 24 '25 13:02 LrLamonier

I am not really an expert on nextjs so I have no intuition here. I'd recommend sharing a repo, so I can check your setup myself

bbohlender avatar Feb 26 '25 11:02 bbohlender

While creating the repo I found where the issue is happening.

TL;DR: the error is thrown when the UI component is inside a <Suspense /> boundary that is inside a server component.

The structure of the page where I am displaying the content is:

<section>
  <Suspense>
    <Canvas>
      <UiComponent />
    </Canvas>
  </Suspense>
</section>

This structure is divided in two: . <section /> is a server component, meaning it is rendered in the server . all the rest is Three-related and must be client components

So the division is:

<section>
  <Suspense>
//// server ////

//// client ////
    <Canvas>
      <UiComponent />
    </Canvas>
//// client ////

//// server ////
  </Suspense>
</section>

In this setup a hydration error is thrown. However, if the suspense is moved into the client component, it works.

<section>
//// server ////

//// client ////
  <Suspense> // suspense in the client component
    <Canvas>
      <UiComponent />
    </Canvas>
  </Suspense>
//// client ////

//// server ////
</section>

As for why this happens, I have no idea. And still I was not being able to reproduce the solution in my project. It turns out that Next.js has an application-wide suspense boundary if you create a component in the loading.tsx file. There's an error even if loading is a client component, because it is merely a fallback, not the boundary itself.

I created a repo with code to reproduce the error happening in the two ways I described above as well as the expected behavior. Right here -> https://github.com/LrLamonier/nextjs-uikit-hydration-error

In the README there are detailed instructions on how to run the project and observe the error.

It is very, very specific, so if my explanation wasn't very good please tell me so I can try and elaborate on whatever's not clear.

LrLamonier avatar Feb 28 '25 05:02 LrLamonier

@LrLamonier can you confirm if this error happens with uikit 1.0 (currently in alpha)?

bbohlender avatar Sep 26 '25 16:09 bbohlender

@bbohlender my apologies, I have long since moved on from that project and I removed the dependency entirely before finishing it. I just checked and I no longer have access to the repo where I tried this because it was a client's.

LrLamonier avatar Sep 26 '25 17:09 LrLamonier

@LrLamonier No worries, and sorry from my side for the delayed response. UIKit 1.0 aligns much closer with how r3f works internally so I am assuming the error should be gone. If you or somebody else encounters this issue again, please reopen :)

bbohlender avatar Sep 26 '25 19:09 bbohlender