r3f-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Three Fiber Best Practices
React Three Fiber 最佳实践
Comprehensive guide for React Three Fiber and the Poimandres ecosystem. Contains 70+ rules across 12 categories, prioritized by impact.
这是针对React Three Fiber及Poimandres生态系统的全面指南,包含12个分类下的70+条规则,按影响优先级排序。
Sources & Credits
来源与致谢
Additional tips from 100 Three.js Tips by Utsubo
额外技巧来自Utsubo的100条Three.js技巧
When to Apply
适用场景
Reference these guidelines when:
- Writing new R3F components
- Optimizing R3F performance (re-renders are the #1 issue)
- Using Drei helpers correctly
- Managing state with Zustand
- Implementing post-processing or physics
在以下场景中可参考本指南:
- 编写新的R3F组件
- 优化R3F性能(重渲染是头号问题)
- 正确使用Drei工具函数
- 使用Zustand管理状态
- 实现后期处理或物理效果
Ecosystem Coverage
生态系统覆盖范围
- @react-three/fiber - React renderer for Three.js
- @react-three/drei - Useful helpers and abstractions
- @react-three/postprocessing - Post-processing effects
- @react-three/rapier - Physics engine
- zustand - State management
- leva - Debug GUI
- @react-three/fiber - Three.js的React渲染器
- @react-three/drei - 实用的工具函数与抽象层
- @react-three/postprocessing - 后期处理效果
- @react-three/rapier - 物理引擎
- zustand - 状态管理库
- leva - 调试GUI
Rule Categories by Priority
按优先级划分的规则分类
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Performance & Re-renders | CRITICAL | |
| 2 | useFrame & Animation | CRITICAL | |
| 3 | Component Patterns | HIGH | |
| 4 | Canvas & Setup | HIGH | |
| 5 | Drei Helpers | MEDIUM-HIGH | |
| 6 | Loading & Suspense | MEDIUM-HIGH | |
| 7 | State Management | MEDIUM | |
| 8 | Events & Interaction | MEDIUM | |
| 9 | Post-processing | MEDIUM | |
| 10 | Physics (Rapier) | LOW-MEDIUM | |
| 11 | Leva (Debug GUI) | LOW | |
| 优先级 | 分类 | 影响程度 | 前缀 |
|---|---|---|---|
| 1 | 性能与重渲染 | 关键 | |
| 2 | useFrame与动画 | 关键 | |
| 3 | 组件模式 | 高 | |
| 4 | Canvas与初始化 | 高 | |
| 5 | Drei工具函数 | 中高 | |
| 6 | 加载与Suspense | 中高 | |
| 7 | 状态管理 | 中 | |
| 8 | 事件与交互 | 中 | |
| 9 | 后期处理 | 中 | |
| 10 | 物理效果(Rapier) | 中低 | |
| 11 | Leva(调试GUI) | 低 | |
Quick Reference
快速参考
1. Performance & Re-renders (CRITICAL)
1. 性能与重渲染(关键)
- - NEVER call setState in useFrame
perf-never-set-state-in-useframe - - Isolate components that need React state
perf-isolate-state - - Use Zustand selectors, not entire store
perf-zustand-selectors - - Use transient subscriptions for continuous values
perf-transient-subscriptions - - Memoize expensive components
perf-memo-components - - Use stable keys for dynamic lists
perf-keys-for-lists - - Avoid creating objects/arrays in JSX
perf-avoid-inline-objects - - Understand R3F auto-dispose behavior
perf-dispose-auto - - Toggle visibility instead of remounting
perf-visibility-toggle - - Use r3f-perf for performance monitoring
perf-r3f-perf
- - 绝不要在useFrame中调用setState
perf-never-set-state-in-useframe - - 隔离需要React状态的组件
perf-isolate-state - - 使用Zustand选择器,而非整个store
perf-zustand-selectors - - 对持续变化的值使用瞬态订阅
perf-transient-subscriptions - - 对开销大的组件进行记忆化处理
perf-memo-components - - 为动态列表使用稳定的key
perf-keys-for-lists - - 避免在JSX中创建对象/数组
perf-avoid-inline-objects - - 了解R3F的自动销毁行为
perf-dispose-auto - - 切换可见性而非重新挂载组件
perf-visibility-toggle - - 使用r3f-perf进行性能监控
perf-r3f-perf
2. useFrame & Animation (CRITICAL)
2. useFrame与动画(关键)
- - Use priority for execution order
frame-priority - - Always use delta for animations
frame-delta-time - - Disable useFrame when not needed
frame-conditional-subscription - - Destructure only what you need
frame-destructure-state - - Use invalidate() for on-demand rendering
frame-render-on-demand - - Move heavy work outside useFrame
frame-avoid-heavy-computation
- - 使用priority控制执行顺序
frame-priority - - 动画中始终使用delta时间
frame-delta-time - - 不需要时禁用useFrame
frame-conditional-subscription - - 仅解构所需的状态
frame-destructure-state - - 使用invalidate()实现按需渲染
frame-render-on-demand - - 将繁重计算移到useFrame外部
frame-avoid-heavy-computation
3. Component Patterns (HIGH)
3. 组件模式(高)
- - Use JSX for Three.js objects
component-jsx-elements - - Use attach for non-standard properties
component-attach-prop - - Use primitive for existing objects
component-primitive - - Use extend() for custom classes
component-extend - - Use forwardRef for reusable components
component-forwardref - - Set dispose={null} on shared resources
component-dispose-null
- - 为Three.js对象使用JSX语法
component-jsx-elements - - 为非标准属性使用attach
component-attach-prop - - 为已有对象使用primitive
component-primitive - - 为自定义类使用extend()
component-extend - - 为可复用组件使用forwardRef
component-forwardref - - 对共享资源设置dispose={null}
component-dispose-null
4. Canvas & Setup (HIGH)
4. Canvas与初始化(高)
- - Canvas fills parent container
canvas-size-container - - Configure camera via prop
canvas-camera-default - - Configure WebGL context
canvas-gl-config - - Enable shadows at Canvas level
canvas-shadows - - Choose appropriate frameloop mode
canvas-frameloop - - Configure event handling
canvas-events - - Use linear/flat for correct colors
canvas-linear-flat
- - Canvas填充父容器
canvas-size-container - - 通过props配置相机
canvas-camera-default - - 配置WebGL上下文
canvas-gl-config - - 在Canvas层面启用阴影
canvas-shadows - - 选择合适的帧循环模式
canvas-frameloop - - 配置事件处理
canvas-events - - 使用linear/flat保证颜色正确
canvas-linear-flat
5. Drei Helpers (MEDIUM-HIGH)
5. Drei工具函数(中高)
- - useGLTF with preloading
drei-use-gltf - - useTexture for texture loading
drei-use-texture - - Environment for realistic lighting
drei-environment - - OrbitControls from Drei
drei-orbit-controls - - Html for DOM overlays
drei-html - - Text for 3D text
drei-text - - Instances for optimized instancing
drei-instances - - useHelper for debug visualization
drei-use-helper - - Bounds to fit camera
drei-bounds - - Center to center objects
drei-center - - Float for floating animation
drei-float
- - 结合预加载使用useGLTF
drei-use-gltf - - 使用useTexture加载纹理
drei-use-texture - - 使用Environment实现真实光照
drei-environment - - 使用Drei提供的OrbitControls
drei-orbit-controls - - 使用Html实现DOM叠加层
drei-html - - 使用Text创建3D文本
drei-text - - 使用Instances实现优化的实例化渲染
drei-instances - - 使用useHelper进行调试可视化
drei-use-helper - - 使用Bounds适配相机视角
drei-bounds - - 使用Center居中对象
drei-center - - 使用Float实现悬浮动画
drei-float
6. Loading & Suspense (MEDIUM-HIGH)
6. 加载与Suspense(中高)
- - Wrap async components in Suspense
loading-suspense - - Preload assets with useGLTF.preload
loading-preload - - useProgress for loading UI
loading-use-progress - - Lazy load heavy components
loading-lazy-components - - Handle loading errors
loading-error-boundary
- - 将异步组件包裹在Suspense中
loading-suspense - - 使用useGLTF.preload预加载资源
loading-preload - - 使用useProgress实现加载UI
loading-use-progress - - 懒加载繁重组件
loading-lazy-components - - 处理加载错误
loading-error-boundary
7. State Management (MEDIUM)
7. 状态管理(中)
- - Create focused Zustand stores
state-zustand-store - - Be careful with Three.js objects
state-avoid-objects-in-store - - Fine-grained subscriptions
state-subscribeWithSelector - - Persist state when needed
state-persist - - Separate stores by concern
state-separate-concerns
- - 创建聚焦的Zustand store
state-zustand-store - - 谨慎在store中存储Three.js对象
state-avoid-objects-in-store - - 细粒度订阅
state-subscribeWithSelector - - 需要时持久化状态
state-persist - - 按关注点拆分store
state-separate-concerns
8. Events & Interaction (MEDIUM)
8. 事件与交互(中)
- - Use pointer events on meshes
events-pointer-events - - Prevent event bubbling
events-stop-propagation - - Change cursor on hover
events-cursor-pointer - - Filter raycasting
events-raycast-filter - - Understand event data structure
events-event-data
- - 在网格上使用指针事件
events-pointer-events - - 阻止事件冒泡
events-stop-propagation - - hover时改变光标
events-cursor-pointer - - 过滤射线检测
events-raycast-filter - - 了解事件数据结构
events-event-data
9. Post-processing (MEDIUM)
9. 后期处理(中)
- - Use EffectComposer
postpro-effect-composer - - Common effects reference
postpro-common-effects - - SelectiveBloom for optimized glow
postpro-selective-bloom - - Create custom effects
postpro-custom-shader - - Optimize post-processing
postpro-performance
- - 使用EffectComposer
postpro-effect-composer - - 常用效果参考
postpro-common-effects - - 使用SelectiveBloom实现优化的发光效果
postpro-selective-bloom - - 创建自定义效果
postpro-custom-shader - - 优化后期处理性能
postpro-performance
10. Physics Rapier (LOW-MEDIUM)
10. 物理效果(Rapier)(中低)
- - Basic Rapier setup
physics-setup - - dynamic, fixed, kinematic
physics-body-types - - Choose appropriate colliders
physics-colliders - - Handle collision events
physics-events - - Use ref for physics API
physics-api-ref - - Optimize physics
physics-performance
- - Rapier基础配置
physics-setup - - 动态、固定、运动学类型
physics-body-types - - 选择合适的碰撞体
physics-colliders - - 处理碰撞事件
physics-events - - 使用ref获取物理API
physics-api-ref - - 优化物理效果性能
physics-performance
11. Leva (LOW)
11. Leva(低)
- - Basic Leva usage
leva-basic - - Organize with folders
leva-folders - - Hide in production
leva-conditional
- - Leva基础用法
leva-basic - - 使用文件夹组织配置
leva-folders - - 生产环境中隐藏调试GUI
leva-conditional
How to Use
使用方法
Read individual rule files for detailed explanations and code examples:
rules/perf-never-set-state-in-useframe.md
rules/drei-use-gltf.md
rules/state-zustand-selectors.md阅读单个规则文件获取详细说明与代码示例:
rules/perf-never-set-state-in-useframe.md
rules/drei-use-gltf.md
rules/state-zustand-selectors.mdFull Compiled Document
完整编译文档
For the complete guide with all rules expanded:
../R3F_BEST_PRACTICES.md包含所有规则详细内容的完整指南:
../R3F_BEST_PRACTICES.mdCritical Patterns
关键模式
NEVER setState in useFrame
绝不要在useFrame中调用setState
jsx
// BAD - 60 re-renders per second!
function BadComponent() {
const [position, setPosition] = useState(0);
useFrame(() => {
setPosition(p => p + 0.01); // NEVER DO THIS
});
return <mesh position-x={position} />;
}
// GOOD - Mutate refs directly
function GoodComponent() {
const meshRef = useRef();
useFrame(() => {
meshRef.current.position.x += 0.01;
});
return <mesh ref={meshRef} />;
}jsx
// BAD - 60 re-renders per second!
function BadComponent() {
const [position, setPosition] = useState(0);
useFrame(() => {
setPosition(p => p + 0.01); // NEVER DO THIS
});
return <mesh position-x={position} />;
}
// GOOD - Mutate refs directly
function GoodComponent() {
const meshRef = useRef();
useFrame(() => {
meshRef.current.position.x += 0.01;
});
return <mesh ref={meshRef} />;
}Zustand Selectors
Zustand选择器
jsx
// BAD - Re-renders on ANY store change
const store = useGameStore();
// GOOD - Only re-renders when playerX changes
const playerX = useGameStore(state => state.playerX);
// BETTER - No re-renders, direct mutation
useFrame(() => {
const { value } = useStore.getState();
ref.current.position.x = value;
});jsx
// BAD - Re-renders on ANY store change
const store = useGameStore();
// GOOD - Only re-renders when playerX changes
const playerX = useGameStore(state => state.playerX);
// BETTER - No re-renders, direct mutation
useFrame(() => {
const { value } = useStore.getState();
ref.current.position.x = value;
});Drei useGLTF
Drei useGLTF
jsx
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
// Preload for instant loading
useGLTF.preload('/model.glb');jsx
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
// Preload for instant loading
useGLTF.preload('/model.glb');Suspense Loading
Suspense加载
jsx
function App() {
return (
<Canvas>
<Suspense fallback={<Loader />}>
<Model />
</Suspense>
</Canvas>
);
}jsx
function App() {
return (
<Canvas>
<Suspense fallback={<Loader />}>
<Model />
</Suspense>
</Canvas>
);
}r3f-perf Monitoring
r3f-perf性能监控
jsx
import { Perf } from 'r3f-perf';
function App() {
return (
<Canvas>
<Perf position="top-left" />
<Scene />
</Canvas>
);
}jsx
import { Perf } from 'r3f-perf';
function App() {
return (
<Canvas>
<Perf position="top-left" />
<Scene />
</Canvas>
);
}Toggle Visibility (Not Remounting)
切换可见性(而非重新挂载)
jsx
// BAD: Remounting destroys and recreates
{showModel && <Model />}
// GOOD: Toggle visibility, keeps instance alive
<Model visible={showModel} />jsx
// BAD: Remounting destroys and recreates
{showModel && <Model />}
// GOOD: Toggle visibility, keeps instance alive
<Model visible={showModel} />