
React Three Fiber简称 R3F是 Three.js 的 React 渲染器它让你能够像写普通 React 组件一样用声明式的 JSX 语法构建 3D 场景。与直接在 React 生命周期中手动操作 Three.js 对象的命令式写法相比R3F 能让代码更清晰、可复用、易于维护。一、核心概念声明式 3D 编程R3F 的本质是一个自定义 React 协调器它能够将 JSX 元素转换成 Three.js 对象。当你写mesh /时背后实际执行的是new THREE.Mesh()并将 props 作为属性应用到该实例上。与传统的 Three.js 代码对比差异一目了然命令式纯 Three.jsconst scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(75, w/h, 0.1, 1000); const mesh new THREE.Mesh(geometry, material); scene.add(mesh); // 还需手动管理渲染循环、清理等...声明式R3Fconst App () ( Canvas camera{{ position: [0, 0, 5] }} ambientLight / mesh boxGeometry / meshStandardMaterial colororange / /mesh /Canvas );Canvas /组件是 R3F 的入口它会自动创建场景、相机、渲染器并处理渲染循环。你只需要关注放什么和怎么动而不是底层如何实现。二、快速开始1. 安装依赖npm install three react-three/fiberreact-three/fiber依赖three作为对等依赖必须一并安装。2. 基础场景示例import { Canvas, useFrame } from react-three/fiber; import { useRef, useState } from react; function RotatingBox() { const meshRef useRef(); const [hovered, setHover] useState(false); const [clicked, setClick] useState(false); // 每一帧执行让立方体旋转 useFrame((state, delta) { meshRef.current.rotation.x delta; // 使用 delta 确保动画速度与帧率解耦 }); return ( mesh ref{meshRef} scale{clicked ? 1.5 : 1} onClick{() setClick(!clicked)} onPointerOver{() setHover(true)} onPointerOut{() setHover(false)} boxGeometry args{[1, 1, 1]} / meshStandardMaterial color{hovered ? hotpink : orange} / /mesh ); } export default function App() { return ( Canvas ambientLight intensity{0.5} / pointLight position{[10, 10, 10]} / RotatingBox / /Canvas ); }⚠️注意使用meshStandardMaterial或meshPhysicalMaterial等基于物理的材质时必须添加光源才能看到物体否则物体将显示为黑色。3. TypeScript 支持R3F 提供了完整的 TypeScript 类型定义。你可以通过ThreeElements来为自定义组件声明 props 类型import { ThreeElements } from react-three/fiber; function Box(props: ThreeElements[mesh]) { // ... }三、核心组件与 Hooks1. Canvas 组件核心属性Canvas 组件是 R3F 的根容器支持以下常用配置属性:属性默认值说明camera{ fov: 75, near: 0.1, far: 1000, position: [0,0,5] }相机配置frameloopalways渲染模式always(持续)/demand(按需)/never(停止)shadowsfalse是否开启阴影映射dpr[1, 2]设备像素比范围flatfalse设为true时禁用色调映射orthographicfalse是否使用正交相机2. 核心 Hooks 详解Hook用途典型场景useFrame在每一帧动画中执行回调连续动画旋转、移动、物理模拟、实时数据更新useThree访问 Three.js 核心对象scene、camera、gl、size、viewport获取相机位置、窗口尺寸、手动控制渲染useLoader加载并缓存 3D 资源模型、纹理等加载 glTF 模型、图片纹理useGraph处理加载后的 glTF 模型分离场景与动画复杂动画模型的操作3. useFrame 使用示例线速度与 lerp 缓动import { useFrame } from react-three/fiber; import { useRef } from react; import * as THREE from three; function AnimatedCube() { const meshRef useRef(); useFrame((state, delta) { // ✅ 正确使用 delta 确保帧速率独立 meshRef.current.rotation.x delta; meshRef.current.rotation.y delta * 0.8; // ✅ lerp线性插值实现平滑跟随 // 目标位置随鼠标移动 meshRef.current.position.x THREE.MathUtils.lerp( meshRef.current.position.x, state.mouse.x * 2, // 目标值 0.1 // 插值系数 ); }); return mesh ref{meshRef}{/* ... */}/mesh; }使用 delta 的关键意义如果直接用 0.01在高刷新率屏幕144Hz上物体旋转会比低刷新率屏幕60Hz快得多。而delta是两帧之间的时间间隔单位秒用它乘以固定速度值可确保物体无论在任何刷新率下都以相同的实际速度运动。四、扩展工具链react-three/dreireact-three/drei是 R3F 的官方扩展库提供了大量预置的辅助组件能大幅提升开发效率类别组件功能相机控制OrbitControls /鼠标拖拽旋转/缩放场景模型加载useGLTF /一行代码加载并缓存 glTF 模型辅助调试Stats /、Grid /、BoxHelper /性能面板/参考网格3D 文字Text /在 3D 空间渲染文字2D 元素Html /、Sprite /在 3D 空间中嵌入 HTML/2D 平面光影增强Environment /、Sky /、Lightformer /环境贴图/天空盒/高级灯光后处理特效EffectComposer /、Bloom /辉光、景深、动态模糊等模型优化useGLTF.preload /、useTexture /预加载和优化模型/纹理性能物理引擎react-three/rapier集成 Rapier 物理引擎五、状态管理R3F 自身使用 Zustand 作为内部状态管理因此两者天然契合。推荐使用 Zustand 管理需要跨组件共享或影响多个 3D 物体的状态// store.js import { create } from zustand; const useStore create((set) ({ color: #ff0000, setColor: (newColor) set({ color: newColor }), rotationSpeed: 0.01, setRotationSpeed: (speed) set({ rotationSpeed: speed }), })); // 在组件中使用 function ColoredBox() { const color useStore((state) state.color); const rotationSpeed useStore((state) state.rotationSpeed); const meshRef useRef(); useFrame((state, delta) { meshRef.current.rotation.x rotationSpeed * delta; }); return ( mesh ref{meshRef} boxGeometry / meshStandardMaterial color{color} / /mesh ); }设计原则分离 3D 场景逻辑与应用状态将用户交互如按钮、滑块关联的状态用 Zustand 或 Context 管理与 3D 渲染逻辑解耦能显著降低主线程阻塞状态更新方式的选择需要触发 React 组件重新渲染的如切换颜色用 Zustand store仅在每一帧动画中连续变化且不需要驱动 UI 更新的如物体旋转角度直接在useFrame中用ref进行可变操作六、性能优化最佳实践在 R3F 中Three.js 的世界与 React 的渲染机制需要协同工作。以下是最关键的优化准则1. 共享几何体和材质减少创建开销Three.js 对象的创建会涉及 GPU 资源分配和编译代价较高。在组件内复用几何体和材质是首要优化手段。// ✅ 正确使用 useMemo 共享几何体和材质 const geometry useMemo(() new THREE.BoxGeometry(1, 1, 1), []); const material useMemo(() new THREE.MeshStandardMaterial({ color: blue }), []); return ( {positions.map(pos mesh geometry{geometry} material{material} position{pos} /)} / );2. 使用 instance 处理大量相同物体需要渲染上百个相同形状的对象时使用 InstancedMesh 替代多个独立 Mesh可将绘制调用从 N 次减少为 1 次。3. 避免在 useFrame 中使用 setState频繁的 React 状态更新会触发组件重新渲染带来不必要的性能开销。性能敏感的连续动画应直接通过ref.current进行可变更新。// ❌ 错误在 useFrame 中使用 setState const [x, setX] useState(0); useFrame(() setX(x x 0.1)); return mesh position-x{x} /; // ✅ 正确使用 ref 直接修改 const meshRef useRef(); useFrame((state, delta) { meshRef.current.position.x delta; }); return mesh ref{meshRef} /;4. 控制显隐优于挂载/卸载频繁挂载/卸载 Three.js 对象会导致材质重新编译、几何体重新处理。用visible属性控制显隐开销低得多。// ❌ 差频繁挂载卸载 {isVisible mesh.../mesh} // ✅ 好切换可见性 mesh visible{isVisible}.../mesh5. 使用 useLoader 缓存资产import { useLoader } from react-three/fiber; import { GLTFLoader } from three/examples/jsm/loaders/GLTFLoader.js; function Model() { // 自动缓存多个组件加载同一模型只发一次网络请求 const gltf useLoader(GLTFLoader, /model.glb); return primitive object{gltf.scene} /; }useLoader实现了资产级别的缓存无论组件加载多少次模型和纹理都只下载并解析一次。6. 性能监控使用浏览器 DevTools Performance 面板监测帧率和绘制调用数确保目标达到 60 FPS。七、常见陷阱与解决陷阱原因解决方案模型全黑使用 PBR 材质但未添加光源添加ambientLight /directionalLight /动画速度异常未使用deltauseFrame((_, delta) obj.rotation.y speed * delta)性能下降在useFrame中调用setState用ref 直接修改属性内存泄漏组件卸载时未清理 Three.js 资源使用useLoader自动缓存或useEffect返回dispose函数纹理加载慢大量高清纹理未压缩使用 KTX2 格式 useLoader缓存模型不显示相机位置不当或模型尺寸过小添加axesHelper /和gridHelper /辅助调试z-index 不生效在 3D 空间中使用了 CSS 概念使用Html /组件或调整渲染顺序renderOrder八、总结你的需求推荐方案快速搭建 3D 场景R3F Canvas Drei 的OrbitControls /需要状态管理Zustand与 UI 层共享 ref 直接修改动画变量加载模型useLoader(GLTFLoader, url)或 Drei 的useGLTF /需要物理效果react-three/rapier或react-three/cannon性能优化useMemo共享几何体、避免setState在useFrame、切换visible而非挂载需要后期特效Drei 的EffectComposer /Bloom /等处理复杂模型动画useGraph分离场景与动画轨道需要调试辅助Drei 的Stats /Grid /BoxHelper /核心原则在 R3F 中Three.js 的 3D 世界与 React 的声明式 UI 融合但两者各有其性能模型——让 React 管理是什么和何时变让 Three.js 管理如何画。将长期运行的动画和频繁更新的属性交给useFrameref直接操作将需要响应式更新的 UI 状态交给 Zustand 或 React state你的应用就能既流畅又清晰。⚠️ 最后提醒用 R3F 开发 Web3D 虽然降低了 Three.js 入门门槛但仍需对 3D 基础概念坐标系、矩阵、灯光类型、着色器有基本理解否则在排查性能或渲染异常时会遇到不小的阻力。R3F 官方文档中列出的各项陷阱和性能建议建议在实际项目前仔细阅读。