react-three-fiber

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Three Fiber

React Three Fiber

React Three Fiber (R3F) is a React renderer for Three.js. Write declarative, component-based 3D scenes using JSX.
Library Versions (2026)
  • React Three Fiber: v9.5+
  • @react-three/drei: v9.116+
  • @react-three/rapier: v2+
  • @react-three/postprocessing: v3+
  • React: 19+ (concurrent features supported)
React Three Fiber(R3F)是Three.js的React渲染器。你可以使用JSX编写声明式、基于组件的3D场景。
库版本(2026)
  • React Three Fiber: v9.5+
  • @react-three/drei: v9.116+
  • @react-three/rapier: v2+
  • @react-three/postprocessing: v3+
  • React: 19+(支持并发特性)

Decision Frameworks

决策框架

When to Use R3F vs Vanilla Three.js

何时使用R3F vs 原生Three.js

Is your app already React-based?
  → Yes: Use R3F (natural integration)
  → No: Consider vanilla Three.js

Do you need React state management?
  → Yes: Use R3F (seamless state integration)
  → No: Either works

Is the 3D scene the entire app?
  → Yes: Either works (R3F has slight overhead)
  → No, mixed with React UI: Use R3F

Performance-critical with millions of objects?
  → Consider vanilla Three.js for maximum control
  → R3F is fine for 99% of use cases
你的应用是否已基于React构建?
  → 是:使用R3F(自然集成)
  → 否:考虑原生Three.js

你是否需要React状态管理?
  → 是:使用R3F(无缝状态集成)
  → 否:两者均可

3D场景是否是整个应用?
  → 是:两者均可(R3F有轻微性能开销)
  → 否,与React UI混合:使用R3F

场景对性能要求极高且包含数百万个对象?
  → 考虑原生Three.js以获得最大控制权
  → R3F适用于99%的使用场景

When to Use Which State Management

何时使用哪种状态管理方案

Local component state (single mesh color, hover)?
  → useState / useRef

Shared between few components (selected object)?
  → React Context or prop drilling

Global game/app state (score, inventory, settings)?
  → Zustand (recommended for R3F)

Complex state with actions/reducers?
  → Zustand with slices or Redux Toolkit

Need state persistence?
  → Zustand with persist middleware
局部组件状态(单个网格颜色、悬浮状态)?
  → useState / useRef

少量组件间共享状态(选中的对象)?
  → React Context 或属性透传

全局游戏/应用状态(分数、库存、设置)?
  → Zustand(R3F推荐方案)

带动作/ reducer的复杂状态?
  → 带切片的Zustand 或 Redux Toolkit

需要状态持久化?
  → 带持久化中间件的Zustand

When to Use Which Drei Component

何时使用哪种Drei组件

Need camera controls?
  ├─ Orbit around object → OrbitControls
  ├─ First-person → PointerLockControls
  ├─ Map/top-down → MapControls
  └─ Smooth transitions → CameraControls

Need environment lighting?
  ├─ Quick preset → <Environment preset="sunset" />
  ├─ Custom HDR → <Environment files="/env.hdr" />
  └─ Performance-sensitive → <Environment blur={0.5} />

Need text?
  ├─ 3D text in scene → <Text3D />
  ├─ 2D text billboards → <Text />
  └─ HTML overlay → <Html />

Need loading?
  ├─ GLTF models → useGLTF
  ├─ Textures → useTexture
  ├─ Progress UI → useProgress
  └─ Preloading → <Preload all />
需要相机控制?
  ├─ 围绕对象旋转 → OrbitControls
  ├─ 第一人称视角 → PointerLockControls
  ├─ 地图/俯视视角 → MapControls
  └─ 平滑过渡 → CameraControls

需要环境光照?
  ├─ 快速预设 → <Environment preset="sunset" />
  ├─ 自定义HDR → <Environment files="/env.hdr" />
  └─ 对性能敏感 → <Environment blur={0.5} />

需要文本?
  ├─ 场景中的3D文本 → <Text3D />
  ├─ 2D文本广告牌 → <Text />
  └─ HTML覆盖层 → <Html />

需要资源加载?
  ├─ GLTF模型 → useGLTF
  ├─ 纹理 → useTexture
  ├─ 进度UI → useProgress
  └─ 预加载 → <Preload all />

Core Setup

核心设置

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

function App() {
  return (
    <Canvas
      camera={{ position: [0, 0, 5], fov: 75 }}
      gl={{ antialias: true }}
      shadows
    >
      <ambientLight intensity={0.5} />
      <directionalLight position={[10, 10, 5]} castShadow />
      <mesh>
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="orange" />
      </mesh>
    </Canvas>
  )
}
jsx
import { Canvas } from '@react-three/fiber'

function App() {
  return (
    <Canvas
      camera={{ position: [0, 0, 5], fov: 75 }}
      gl={{ antialias: true }}
      shadows
    >
      <ambientLight intensity={0.5} />
      <directionalLight position={[10, 10, 5]} castShadow />
      <mesh>
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="orange" />
      </mesh>
    </Canvas>
  )
}

Canvas Props

Canvas属性

jsx
<Canvas
  camera={{ position, fov, near, far }}  // Camera config
  gl={{ antialias, alpha, powerPreference }}  // WebGL context
  shadows  // Enable shadow maps
  dpr={[1, 2]}  // Device pixel ratio range
  frameloop="demand"  // "always" | "demand" | "never"
  style={{ width: '100%', height: '100vh' }}
  onCreated={({ gl, scene, camera }) => {}}  // Access internals
/>
jsx
<Canvas
  camera={{ position, fov, near, far }}  // 相机配置
  gl={{ antialias, alpha, powerPreference }}  // WebGL上下文
  shadows  // 启用阴影贴图
  dpr={[1, 2]}  // 设备像素比范围
  frameloop="demand"  // "always" | "demand" | "never"
  style={{ width: '100%', height: '100vh' }}
  onCreated={({ gl, scene, camera }) => {}}  // 访问内部实例
/>

Essential Hooks

核心Hooks

useFrame - Animation Loop

useFrame - 动画循环

jsx
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'

function SpinningBox() {
  const meshRef = useRef()

  useFrame((state, delta) => {
    // state: { clock, camera, scene, gl, pointer, ... }
    meshRef.current.rotation.y += delta
    meshRef.current.position.y = Math.sin(state.clock.elapsedTime)
  })

  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  )
}
jsx
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'

function SpinningBox() {
  const meshRef = useRef()

  useFrame((state, delta) => {
    // state: { clock, camera, scene, gl, pointer, ... }
    meshRef.current.rotation.y += delta
    meshRef.current.position.y = Math.sin(state.clock.elapsedTime)
  })

  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  )
}

useThree - Access Internals

useThree - 访问内部实例

jsx
import { useThree } from '@react-three/fiber'

function CameraLogger() {
  const { camera, gl, scene, size, viewport, pointer } = useThree()
  // viewport: { width, height } in Three.js units
  // size: { width, height } in pixels
  // pointer: normalized mouse position (-1 to 1)
  return null
}
jsx
import { useThree } from '@react-three/fiber'

function CameraLogger() {
  const { camera, gl, scene, size, viewport, pointer } = useThree()
  // viewport: Three.js单位下的{ width, height }
  // size: 像素单位下的{ width, height }
  // pointer: 归一化鼠标位置(-1到1)
  return null
}

useLoader - Asset Loading

useLoader - 资源加载

jsx
import { useLoader } from '@react-three/fiber'
import { TextureLoader } from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

function Model() {
  const gltf = useLoader(GLTFLoader, '/model.glb')
  const texture = useLoader(TextureLoader, '/texture.jpg')

  return <primitive object={gltf.scene} />
}
jsx
import { useLoader } from '@react-three/fiber'
import { TextureLoader } from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

function Model() {
  const gltf = useLoader(GLTFLoader, '/model.glb')
  const texture = useLoader(TextureLoader, '/texture.jpg')

  return <primitive object={gltf.scene} />
}

JSX to Three.js Mapping

JSX与Three.js映射

jsx
// Three.js class → camelCase JSX element
// Constructor args → args prop (array)
// Properties → props

// THREE.Mesh
<mesh position={[0, 1, 0]} rotation={[0, Math.PI, 0]} scale={1.5}>
  {/* THREE.BoxGeometry(1, 2, 1) */}
  <boxGeometry args={[1, 2, 1]} />
  {/* THREE.MeshStandardMaterial({ color: 'red' }) */}
  <meshStandardMaterial color="red" roughness={0.5} />
</mesh>

// Nested properties use dash notation
<directionalLight
  position={[5, 5, 5]}
  castShadow
  shadow-mapSize={[2048, 2048]}
  shadow-camera-far={50}
/>

// Attach to parent properties
<mesh>
  <boxGeometry />
  <meshStandardMaterial>
    <texture attach="map" image={img} />
  </meshStandardMaterial>
</mesh>
jsx
// Three.js类 → 小驼峰式JSX元素
// 构造函数参数 → args属性(数组)
// 属性 → 组件props

// THREE.Mesh
<mesh position={[0, 1, 0]} rotation={[0, Math.PI, 0]} scale={1.5}>
  {/* THREE.BoxGeometry(1, 2, 1) */}
  <boxGeometry args={[1, 2, 1]} />
  {/* THREE.MeshStandardMaterial({ color: 'red' }) */}
  <meshStandardMaterial color="red" roughness={0.5} />
</mesh>

// 嵌套属性使用短横线命名法
<directionalLight
  position={[5, 5, 5]}
  castShadow
  shadow-mapSize={[2048, 2048]}
  shadow-camera-far={50}
/>

// 附加到父元素属性
<mesh>
  <boxGeometry />
  <meshStandardMaterial>
    <texture attach="map" image={img} />
  </meshStandardMaterial>
</mesh>

Drei - Essential Helpers

Drei - 核心工具库

Drei provides production-ready abstractions. Install:
@react-three/drei
jsx
import {
  OrbitControls,
  PerspectiveCamera,
  Environment,
  useGLTF,
  useTexture,
  Text,
  Html,
  Float,
  Stage,
  ContactShadows,
  Sky,
  Stars,
} from '@react-three/drei'
Drei提供生产级别的抽象封装。安装命令:
@react-three/drei
jsx
import {
  OrbitControls,
  PerspectiveCamera,
  Environment,
  useGLTF,
  useTexture,
  Text,
  Html,
  Float,
  Stage,
  ContactShadows,
  Sky,
  Stars,
} from '@react-three/drei'

Common Drei Components

常用Drei组件

jsx
// Camera controls
<OrbitControls enableDamping dampingFactor={0.05} />

// Environment lighting (HDR)
<Environment preset="sunset" background />
// Presets: apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse

// Load GLTF with draco support
const { scene, nodes, materials } = useGLTF('/model.glb')
useGLTF.preload('/model.glb')

// Load textures
const [colorMap, normalMap] = useTexture(['/color.jpg', '/normal.jpg'])

// 3D Text
<Text fontSize={1} color="white" anchorX="center" anchorY="middle">
  Hello World
</Text>

// HTML overlay in 3D space
<Html position={[0, 2, 0]} center transform occlude>
  <div className="label">Click me</div>
</Html>

// Floating animation
<Float speed={2} rotationIntensity={0.5} floatIntensity={1}>
  <mesh>...</mesh>
</Float>

// Quick studio lighting
<Stage environment="city" intensity={0.5}>
  <Model />
</Stage>

// Soft shadows on ground
<ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
jsx
// 相机控制
<OrbitControls enableDamping dampingFactor={0.05} />

// 环境光照(HDR)
<Environment preset="sunset" background />
// 预设值:apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse

// 加载带draco支持的GLTF模型
const { scene, nodes, materials } = useGLTF('/model.glb')
useGLTF.preload('/model.glb')

// 加载纹理
const [colorMap, normalMap] = useTexture(['/color.jpg', '/normal.jpg'])

// 3D文本
<Text fontSize={1} color="white" anchorX="center" anchorY="middle">
  Hello World
</Text>

// 3D空间中的HTML覆盖层
<Html position={[0, 2, 0]} center transform occlude>
  <div className="label">点击我</div>
</Html>

// 悬浮动画
<Float speed={2} rotationIntensity={0.5} floatIntensity={1}>
  <mesh>...</mesh>
</Float>

// 快速工作室光照
<Stage environment="city" intensity={0.5}>
  <Model />
</Stage>

// 地面软阴影
<ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />

Event Handling

事件处理

jsx
<mesh
  onClick={(e) => {
    e.stopPropagation()
    console.log('clicked', e.point, e.face)
  }}
  onPointerOver={(e) => setHovered(true)}
  onPointerOut={(e) => setHovered(false)}
  onPointerMove={(e) => console.log(e.point)}
  onPointerDown={(e) => {}}
  onPointerUp={(e) => {}}
  onDoubleClick={(e) => {}}
  onContextMenu={(e) => {}}
>
Event object includes:
point
,
face
,
faceIndex
,
distance
,
object
,
eventObject
,
camera
,
ray
.
jsx
<mesh
  onClick={(e) => {
    e.stopPropagation()
    console.log('点击了', e.point, e.face)
  }}
  onPointerOver={(e) => setHovered(true)}
  onPointerOut={(e) => setHovered(false)}
  onPointerMove={(e) => console.log(e.point)}
  onPointerDown={(e) => {}}
  onPointerUp={(e) => {}}
  onDoubleClick={(e) => {}}
  onContextMenu={(e) => {}}
>
事件对象包含:
point
face
faceIndex
distance
object
eventObject
camera
ray

State Management

状态管理

With Zustand (Recommended)

使用Zustand(推荐)

jsx
import { create } from 'zustand'

const useStore = create((set) => ({
  score: 0,
  gameState: 'idle',
  addScore: (points) => set((state) => ({ score: state.score + points })),
  startGame: () => set({ gameState: 'playing' }),
}))

function ScoreDisplay() {
  const score = useStore((state) => state.score)
  return <Text>{score}</Text>
}

function GameLogic() {
  const addScore = useStore((state) => state.addScore)
  useFrame(() => {
    // Game logic that calls addScore
  })
  return null
}
jsx
import { create } from 'zustand'

const useStore = create((set) => ({
  score: 0,
  gameState: 'idle',
  addScore: (points) => set((state) => ({ score: state.score + points })),
  startGame: () => set({ gameState: 'playing' }),
}))

function ScoreDisplay() {
  const score = useStore((state) => state.score)
  return <Text>{score}</Text>
}

function GameLogic() {
  const addScore = useStore((state) => state.addScore)
  useFrame(() => {
    // 调用addScore的游戏逻辑
  })
  return null
}

With React Context

使用React Context

jsx
const GameContext = createContext()

function GameProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <GameContext.Provider value={{ state, dispatch }}>
      {children}
    </GameContext.Provider>
  )
}

// Wrap Canvas content
<Canvas>
  <GameProvider>
    <Scene />
  </GameProvider>
</Canvas>
jsx
const GameContext = createContext()

function GameProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <GameContext.Provider value={{ state, dispatch }}>
      {children}
    </GameContext.Provider>
  )
}

// 包裹Canvas内容
<Canvas>
  <GameProvider>
    <Scene />
  </GameProvider>
</Canvas>

Performance Patterns

性能优化模式

Instancing

实例化渲染

jsx
import { Instances, Instance } from '@react-three/drei'

function Boxes({ count = 1000 }) {
  return (
    <Instances limit={count}>
      <boxGeometry />
      <meshStandardMaterial />
      {Array.from({ length: count }, (_, i) => (
        <Instance
          key={i}
          position={[Math.random() * 100, Math.random() * 100, Math.random() * 100]}
          color={`hsl(${Math.random() * 360}, 50%, 50%)`}
        />
      ))}
    </Instances>
  )
}
jsx
import { Instances, Instance } from '@react-three/drei'

function Boxes({ count = 1000 }) {
  return (
    <Instances limit={count}>
      <boxGeometry />
      <meshStandardMaterial />
      {Array.from({ length: count }, (_, i) => (
        <Instance
          key={i}
          position={[Math.random() * 100, Math.random() * 100, Math.random() * 100]}
          color={`hsl(${Math.random() * 360}, 50%, 50%)`}
        />
      ))}
    </Instances>
  )
}

Selective Rendering

选择性渲染

jsx
// Only re-render when needed
<Canvas frameloop="demand">
  {/* Call invalidate() to trigger render */}
</Canvas>

function Controls() {
  const { invalidate } = useThree()
  return <OrbitControls onChange={() => invalidate()} />
}
jsx
// 仅在需要时重新渲染
<Canvas frameloop="demand">
  {/* 调用invalidate()触发渲染 */}
</Canvas>

function Controls() {
  const { invalidate } = useThree()
  return <OrbitControls onChange={() => invalidate()} />
}

Memoization

记忆化

jsx
// Memoize expensive components
const ExpensiveModel = memo(function ExpensiveModel({ url }) {
  const gltf = useGLTF(url)
  return <primitive object={gltf.scene.clone()} />
})

// Memoize materials/geometries outside components
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 'red' })

function Box() {
  return (
    <mesh geometry={geometry} material={material} />
  )
}
jsx
// 记忆化开销大的组件
const ExpensiveModel = memo(function ExpensiveModel({ url }) {
  const gltf = useGLTF(url)
  return <primitive object={gltf.scene.clone()} />
})

// 在组件外部记忆化材质/几何体
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 'red' })

function Box() {
  return (
    <mesh geometry={geometry} material={material} />
  )
}

Adaptive Performance

自适应性能

jsx
import { PerformanceMonitor, AdaptiveDpr, AdaptiveEvents } from '@react-three/drei'

<Canvas>
  <PerformanceMonitor
    onDecline={() => setQuality('low')}
    onIncline={() => setQuality('high')}
  >
    <AdaptiveDpr pixelated />
    <AdaptiveEvents />
    <Scene quality={quality} />
  </PerformanceMonitor>
</Canvas>
jsx
import { PerformanceMonitor, AdaptiveDpr, AdaptiveEvents } from '@react-three/drei'

<Canvas>
  <PerformanceMonitor
    onDecline={() => setQuality('low')}
    onIncline={() => setQuality('high')}
  >
    <AdaptiveDpr pixelated />
    <AdaptiveEvents />
    <Scene quality={quality} />
  </PerformanceMonitor>
</Canvas>

Related Skills

相关技能

When you need...Use skill
Vanilla Three.js (no React)threejs
Optimize assets before loadingasset-pipeline-3d
Debug visual/performance issuesgraphics-troubleshooting
当你需要...使用技能
原生Three.js(无React)threejs
加载前优化资源asset-pipeline-3d
调试视觉/性能问题graphics-troubleshooting

Reference Files

参考文件

  • references/drei.md - Complete Drei component reference
  • references/physics.md - @react-three/rapier integration
  • references/postprocessing.md - @react-three/postprocessing effects
  • references/state.md - Zustand patterns for R3F
  • references/drei.md - 完整Drei组件参考
  • references/physics.md - @react-three/rapier集成指南
  • references/postprocessing.md - @react-three/postprocessing特效指南
  • references/state.md - R3F的Zustand使用模式