You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Three Fiber懒加载模型组件触发无限重渲染问题求助

问题描述

在React Three Fiber中尝试懒加载JSX模型组件,这些组件通过drei库的useGLTF()加载实际的.gltf/.glb模型。使用ModelsLoader组件按需懒加载时,即便使用了React的memo()或useMemo(),组件仍持续触发无限重渲染,不确定该实现方式是否可行,寻求解决方法。

模型组件示例

import React, { useRef } from 'react';
import { useGLTF } from '@react-three/drei';

export default function OCF155(props) {
  const { nodes } = useGLTF('models/EXAMPLE_MODEL.glb');
  const ref = useRef();
  return (
    <group {...props} ref={ref} dispose={null} type='TopParent'>
      <mesh
        name='EXAMPLE_MODEL'
        castShadow
        receiveShadow
        geometry={nodes.EXAMPLE_MODEL.geometry}
        material={nodes.EXAMPLE_MODEL.material}
        rotation={[Math.PI / 2, 0, 0]}
        scale={1}
      />
    </group>
  );
}

当前使用memo()的ModelsLoader组件代码

import React, { memo, lazy } from 'react';
import Selection from './helpers/Selection';

const ModelsLoader = memo(function ModelsLoader({ models }) {
  return (
    <>
      {models &&
        models.length > 0 &&
        models.map((model, index) => {
          const ModelComponent = lazy(() => import(`./models/${model.name}`));
          return (
            <Selection key={index}>
              <ModelComponent
                position={model.position}
                rotation={model.rotation}
              />
            </Selection>
          );
        })}
    </>
  );
});

export default ModelsLoader;

原本预期只要models列表在渲染过程中不发生变化,memo()就能让组件仅渲染一次,但实际结果不符合预期。


解决方案

1. 核心问题定位

你在map循环的渲染阶段动态执行lazy(() => import(...)),这会导致每次渲染时ModelComponent都是全新的组件引用。React会将其识别为不同的组件,进而销毁旧组件、重新挂载新组件,最终触发无限重渲染循环。

2. 分步修复

步骤1:缓存懒加载组件,避免重复创建

不要在渲染阶段动态生成lazy组件,而是通过缓存对象存储已加载的组件,确保同一模型的组件引用始终稳定:

import React, { memo, lazy, useMemo } from 'react';
import Selection from './helpers/Selection';

// 缓存已加载的模型组件,避免重复创建lazy引用
const modelComponentCache = {};

const ModelsLoader = memo(function ModelsLoader({ models }) {
  // 用useMemo缓存处理后的模型组件列表,仅当models变化时重新计算
  const processedModels = useMemo(() => {
    if (!models || models.length === 0) return [];

    return models.map(model => {
      // 优先从缓存取组件,无则创建并缓存
      if (!modelComponentCache[model.name]) {
        modelComponentCache[model.name] = lazy(() => import(`./models/${model.name}`));
      }
      return { ...model, Component: modelComponentCache[model.name] };
    });
  }, [models]);

  return (
    <>
      {processedModels.map((model) => (
        {/* 优先用模型name作为key,避免index导致的组件复用问题 */}
        <Selection key={model.name}>
          <model.Component
            position={model.position}
            rotation={model.rotation}
          />
        </Selection>
      ))}
    </>
  );
});

export default ModelsLoader;

步骤2:优化模型组件的稳定性

给模型组件包裹memo,避免props未变化时的不必要重渲染(useGLTF本身有缓存,但组件层面的优化更稳妥):

import React, { useRef, memo } from 'react';
import { useGLTF } from '@react-three/drei';

const OCF155 = memo(function OCF155(props) {
  const { nodes } = useGLTF('models/EXAMPLE_MODEL.glb');
  const ref = useRef();
  return (
    <group {...props} ref={ref} dispose={null} type='TopParent'>
      <mesh
        name='EXAMPLE_MODEL'
        castShadow
        receiveShadow
        geometry={nodes.EXAMPLE_MODEL.geometry}
        material={nodes.EXAMPLE_MODEL.material}
        rotation={[Math.PI / 2, 0, 0]}
        scale={1}
      />
    </group>
  );
});

export default OCF155;

步骤3:确保models props的引用稳定

如果父组件传递的models是每次渲染都重新创建的数组(比如直接在render中定义models=[{...}]),memo会因为数组引用变化而失效。需要在父组件中用useMemo缓存models:

// 父组件示例
import { useMemo } from 'react';
import ModelsLoader from './ModelsLoader';

function ParentComponent() {
  // 用useMemo缓存models数组,确保引用稳定
  const models = useMemo(() => [
    { name: 'OCF155', position: [0, 0, 0], rotation: [0, 0, 0] },
    // 其他模型配置
  ], []);

  return <ModelsLoader models={models} />;
}

3. 额外注意事项

  • 必须配合Suspense使用懒加载组件,在ModelsLoader的父组件外层添加加载状态:
import { Suspense } from 'react';

// 父组件中
<Suspense fallback={<div>模型加载中...</div>}>
  <ModelsLoader models={models} />
</Suspense>
  • 避免使用index作为组件key,优先使用模型唯一标识(如name),防止列表顺序变化时组件错误复用。

内容的提问来源于stack exchange,提问作者Jakub Pabis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:50:22