关于 r3f-best-practices
面向 React Three Fiber 开发者的实践指南,涵盖性能、动画、组件和 Poimandres 生态工具。它按影响优先级组织规则,并提供规则文件与示例供针对性查阅。
主要功能
- 01涵盖 70 多条实践规则
- 02按影响优先级分类
- 03指导性能与重渲染优化
- 04覆盖动画、状态和交互
- 05提供规则文件及代码示例
适用场景
- 01优化 React Three Fiber 场景性能
- 02实现 useFrame 动画与状态管理
- 03使用 Drei 加载和处理 3D 资源
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ emalorenzo/ three-agent-skills --skill r3f-best-practices安装后在 Claude Code 中输入/r3f-best-practices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
rules/_sections.mddrei-use-gltf.mdframe-delta-time.mdloading-suspense.mdperf-never-set-state-in-useframe.mdperf-r3f-perf.mdperf-visibility-toggle.mdperf-zustand-selectors.md详细介绍
React Three Fiber 最佳实践
React Three Fiber 和 Poimandres 生态系统的综合指南。包含 12 个类别、70 多条规则,并按影响力排序。
来源与致谢
更多技巧请参阅 Utsubo 的 100 条 Three.js 技巧
适用时机
在以下情况下参考这些指南:
- 编写新的 R3F 组件
- 优化 R3F 性能(重新渲染是头号问题)
- 正确使用 Drei 辅助工具
- 使用 Zustand 管理状态
- 实现后期处理或物理效果
生态系统覆盖范围
- @react-three/fiber - Three.js 的 React 渲染器
- @react-three/drei - 实用辅助工具和抽象
- @react-three/postprocessing - 后期处理效果
- @react-three/rapier - 物理引擎
- zustand - 状态管理
- leva - 调试 GUI
按优先级划分的规则类别
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 性能与重新渲染 | CRITICAL | perf- |
| 2 | useFrame 与动画 | CRITICAL | frame- |
| 3 | 组件模式 | HIGH | component- |
| 4 | Canvas 与设置 | HIGH | canvas- |
| 5 | Drei 辅助工具 | MEDIUM-HIGH | drei- |
| 6 | 加载与 Suspense | MEDIUM-HIGH | loading- |
| 7 | 状态管理 | MEDIUM | state- |
| 8 | 事件与交互 | MEDIUM | events- |
| 9 | 后期处理 | MEDIUM | postpro- |
| 10 | 物理(Rapier) | LOW-MEDIUM | physics- |
| 11 | Leva(调试 GUI) | LOW | leva- |
快速参考
1. 性能与重新渲染(CRITICAL)
perf-never-set-state-in-useframe- 绝不要在 useFrame 中调用 setStateperf-isolate-state- 隔离需要 React 状态的组件perf-zustand-selectors- 使用 Zustand 选择器,而不是整个 storeperf-transient-subscriptions- 对连续变化的值使用瞬时订阅perf-memo-components- 对开销大的组件进行记忆化perf-keys-for-lists- 为动态列表使用稳定的键perf-avoid-inline-objects- 避免在 JSX 中创建对象/数组perf-dispose-auto- 了解 R3F 的自动释放行为perf-visibility-toggle- 切换可见性,而不是重新挂载perf-r3f-perf- 使用 r3f-perf 监控性能
2. useFrame 与动画(CRITICAL)
frame-priority- 使用优先级控制执行顺序frame-delta-time- 始终在动画中使用 deltaframe-conditional-subscription- 不需要时禁用 useFrameframe-destructure-state- 仅解构所需内容frame-render-on-demand- 使用 invalidate() 按需渲染frame-avoid-heavy-computation- 将繁重的计算移出 useFrame
3. 组件模式(HIGH)
component-jsx-elements- 使用 JSX 创建 Three.js 对象component-attach-prop- 对非标准属性使用 attachcomponent-primitive- 对现有对象使用 primitivecomponent-extend- 对自定义类使用 extend()component-forwardref- 使用 forwardRef 创建可复用组件component-dispose-null- 对共享资源设置 dispose={null}
4. Canvas 与设置(HIGH)
canvas-size-container- 让 Canvas 填满父容器canvas-camera-default- 通过属性配置相机canvas-gl-config- 配置 WebGL 上下文canvas-shadows- 在 Canvas 层级启用阴影canvas-frameloop- 选择合适的帧循环模式canvas-events- 配置事件处理canvas-linear-flat- 使用 linear/flat 以确保颜色正确
5. Drei 辅助工具(MEDIUM-HIGH)
drei-use-gltf- 使用带预加载功能的 useGLTFdrei-use-texture- 使用 useTexture 加载纹理drei-environment- 使用 Environment 实现逼真的光照drei-orbit-controls- 使用来自 Drei 的 OrbitControlsdrei-html- 使用 Html 添加 DOM 覆盖层drei-text- 使用 Text 添加 3D 文本drei-instances- 使用 Instances 优化实例化drei-use-helper- 使用 useHelper 进行调试可视化drei-bounds- 使用 Bounds 调整相机取景drei-center- 使用 Center 将对象居中drei-float- 使用 Float 实现浮动动画
6. 加载与 Suspense(MEDIUM-HIGH)
loading-suspense- 使用 Suspense 包裹异步组件loading-preload- 使用 useGLTF.preload 预加载资源loading-use-progress- 使用 useProgress 显示加载界面loading-lazy-components- 延迟加载较重的组件loading-error-boundary- 处理加载错误
7. 状态管理(MEDIUM)
state-zustand-store- 创建职责明确的 Zustand storestate-avoid-objects-in-store- 谨慎处理 Three.js 对象state-subscribeWithSelector- 使用细粒度订阅state-persist- 按需持久化状态state-separate-concerns- 按职责拆分 store
8. 事件与交互(MEDIUM)
events-pointer-events- 在网格上使用指针事件events-stop-propagation- 阻止事件冒泡events-cursor-pointer- 悬停时更改光标events-raycast-filter- 筛选光线投射events-event-data- 了解事件数据结构
9. 后期处理(MEDIUM)
postpro-effect-composer- 使用 EffectComposerpostpro-common-effects- 常见效果参考postpro-selective-bloom- 使用 SelectiveBloom 优化辉光postpro-custom-shader- 创建自定义效果postpro-performance- 优化后期处理
10. Rapier 物理(LOW-MEDIUM)
physics-setup- Rapier 基本设置physics-body-types- dynamic、fixed、kinematicphysics-colliders- 选择合适的碰撞体physics-events- 处理碰撞事件physics-api-ref- 使用 ref 调用物理 APIphysics-performance- 优化物理效果
11. Leva(LOW)
leva-basic- Leva 基本用法leva-folders- 使用文件夹整理leva-conditional- 在生产环境中隐藏
使用方法
阅读各个规则文件,了解详细说明和代码示例:
rules/perf-never-set-state-in-useframe.md
rules/drei-use-gltf.md
rules/state-zustand-selectors.md
完整汇编文档
查看包含所有扩展规则的完整指南:../R3F_BEST_PRACTICES.md
关键模式
切勿在 useFrame 中调用 setState
// 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 选择器
// 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
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 加载
function App() {
return (
<Canvas>
<Suspense fallback={<Loader />}>
<Model />
</Suspense>
</Canvas>
);
}
r3f-perf 监控
import { Perf } from 'r3f-perf';
function App() {
return (
<Canvas>
<Perf position="top-left" />
<Scene />
</Canvas>
);
}
切换可见性(而非重新挂载)
// BAD: Remounting destroys and recreates
{showModel && <Model />}
// GOOD: Toggle visibility, keeps instance alive
<Model visible={showModel} />
评论
支持 Markdown