philolegein
philolegein

Reputation: 1535

NextJS re-rendering component on route change in prod (possibly due to dynamic?)

I'm having an issue where I have a dynamically loaded client-side component (because I'm using R3F and ThreeJS, and apparently it needs to be that way), and on route change in production (but not in dev) it's re-rendering.

I'm not sure if I'm doing something wrong with next/dynamic, or if I need to do something specifically because of drei/view, or something else entirely.

My component tree, after everything's included, looks like this:

App
  Layout
    Providers
      PageLayout
        Header
        Hero
          HeroThree
            Model           // <- this is (re-) rendering
            HeroThreeImage
            ...
          LoadStaticHero
        {children}
        Footer

Here's the Model component:

'use client';

import { Suspense } from 'react';
import dynamic from 'next/dynamic';

import { FboScene } from 'components/three/FboScene';

const View = dynamic(() => import('components/core/View')
    .then((mod) => mod.View), {
        ssr: false
    }
);

export function Model(props) {
    const {
        orbit, // previously used, but removed to help with debugging
        ...fboSceneProps
    } = props;
    console.log('Re-rendering model')

    return (
        <View>
            <Suspense fallback={null}>
                <FboScene {...fboSceneProps} />
            </Suspense>
        </View>
    )
}

Using DevTools in Chrome in the development environment, everything is fine. But, when I push to production on Vercel, it re-renders this component on every navigation change.

Why is that happening / how do I stop it?

Aside: I can't figure out how to get DevTools working on a NextJS production build (the Next debugging docs don't discuss it, the Chrome console points to outdated React docs, and the current (AFAICT) React docs only talk about CRA and Weback); hence the console.log, which I've also placed on components above and below this in the tree. Based on the logs, nothing above this in the tree is being gratuitously re-rendered.

Looking around SO, there seem to be several questions the other direction (i.e., how do I force something to re-render), or they're both old and for other environments (e.g., this one), predating all of the Next server/client-side splitting and next/dynamic.

In case the dynamically-loaded code itself is relevant, here's the View component:

// components/core/View.js
'use client';

import { forwardRef, useImperativeHandle, useRef } from 'react';
import { View as DreiView, OrbitControls } from '@react-three/drei';

import { Three } from 'utils/Three';

const View = forwardRef(({ children, orbit, ...props }, ref) => {
    const localRef = useRef(null);
    useImperativeHandle(ref, () => localRef.current);

    return (
        <>
            <div ref={localRef} {...props} />
            <Three>
                <DreiView track={localRef}>
                    {children}
                    {orbit && <OrbitControls />}
                </DreiView>
            </Three>
        </>
    )
})

View.displayName = 'View';

export { View };

TBH, I've been chasing this for over a week, and have "fixed" lots of other things, so this may well not be the issue. If looking at the code, it doesn't seem likely to have anything to do with the next/dynamic, I'm very open to other places to look to help diagnose why this is happening.

Upvotes: 0

Views: 18

Answers (0)

Related Questions