Why am I getting this useLayoutEffect warning (not in a test)

Viewed 255

I have a newly created, near-empty next/react/fiber project, with a fiber Canvas. It throws the following warning every time I compile.

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
    at Canvas (C:\MyLocalFiles\Stratum\repos\cfgnext-updated\node_modules\@react-three\fiber\dist\react-three-fiber.cjs.dev.js:155:3)

Here is the smallest example that illustrates the problem, followed by package.json:

import { Canvas } from '@react-three/fiber'

export default function Home() {
  return (
    <div>
        <Canvas>
        </Canvas>
    </div>
  )
}

package.json

{
  "name": "cfgnext-updated",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@react-three/drei": "^9.0.1",
    "@react-three/fiber": "^8.0.6",
    "babel-plugin-styled-components": "^2.0.6",
    "next": "12.1.4",
    "react": "18.0.0",
    "react-dom": "18.0.0",
    "styled-components": "^5.3.5"
  },
  "devDependencies": {
    "eslint": "8.12.0",
    "eslint-config-next": "12.1.4"
  }
}

When I fill in the Canvas with other fiber components everything seems to work perfectly.

Could somebody tell me:

  1. Is this, in fact, a legitimate warning? If not
  2. Is there a way to eliminate it?

tia, Bill

2 Answers

@juliomalves comment above was the answer. Thank you. I was looking in all the wrong places.

Here is the updated code, split into a page and a dynamically loaded component (with some new content for visibility).

import dynamic from 'next/dynamic'
import styled from "styled-components"

const Scene = dynamic(
  () => import('./scene'),
  { ssr: false }
)

export default function App() {
  return (
    <div>
      <ModelDiv>
          <Scene/>
      </ModelDiv>
    </div>
  )
}

const ModelDiv = styled.div`
  display: block;
  background-color: lightblue;
    width: 100%;
  height: 100vh;
`;

The corresponding component in scene.js:

import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'

export default function Scene() {
    return (
            <Canvas>
                <ambientLight intensity={1} />
                <directionalLight position={[0, 1, 5]} intensity={1} />
                <OrbitControls />
                <mesh>
                    <boxGeometry args={[1, 1, 1]} />
                    <meshStandardMaterial color="yellow" />
                </mesh>
            </Canvas>
    )
}

By running useLayoutEffect on the server you can potentially send different html content than the one that the app will produce when running on the client for the first time, hence the warning. One way to fix this is not to render the component that uses useLayoutEffect on the server.

You can do this by checking if the window object is defined. When it is defined it means that your code is running on the client, and only then you should render your canvas component.

Related