在Gatsby+React Three Fiber中使用Context实例化网格报错
解决Gatsby + R3F实例化网格的Context与
instances未定义问题 核心问题定位
- 全局包裹Context Provider会导致R3F钩子在Canvas外部执行,触发
Hooks can only be used within the Canvas component错误 instances未定义是因为Context数据没有正确传递到Canvas内的组件树中
分步解决方案
1. 正确创建Context并限定使用范围
先创建Context,同时封装自定义钩子确保只能在Provider内部使用:
// src/context/InstanceContext.js import { createContext, useContext } from 'react'; const InstanceContext = createContext(null); export const useInstanceContext = () => { const context = useContext(InstanceContext); if (!context) throw new Error('useInstanceContext必须在InstanceContext.Provider内部使用'); return context; }; export default InstanceContext;
2. 在Canvas内部挂载Context Provider
将Provider放在Canvas组件内部,确保所有依赖R3F钩子的组件都处于Canvas上下文内:
// src/pages/your-page.js import { Canvas } from '@react-three/fiber'; import InstanceContext from '../context/InstanceContext'; import Planks from '../components/Planks'; export default function YourPage() { // 定义实例化数据:每个实例的位置、旋转、缩放参数 const instances = [ { position: [0, 0, 0], rotation: [0, 0, 0] }, { position: [2, 0, 0], rotation: [0, Math.PI/4, 0] }, { position: [4, 0, 0], rotation: [0, Math.PI/2, 0] } // 按需添加更多实例 ]; return ( <div style={{ width: '100vw', height: '100vh' }}> <Canvas> {/* 仅在Canvas内部提供Context */} <InstanceContext.Provider value={{ instances }}> <Planks /> {/* 其他场景组件 */} </InstanceContext.Provider> </Canvas> </div> ); }
3. 在Planks组件中正确获取实例数据并使用Merged
确保组件在Canvas树内执行钩子,正确传递instances给Merged组件:
// src/components/Planks.js import { useInstanceContext } from '../context/InstanceContext'; import { Merged, useGLTF } from '@react-three/drei'; export default function Planks() { const { instances } = useInstanceContext(); // 加载目标模型(假设模型中包含名为Plank的网格节点) const { nodes, loaded } = useGLTF('/plank.gltf'); // 等待模型加载完成再渲染实例 if (!loaded) return null; return ( <Merged instances={instances}> <mesh geometry={nodes.Plank.geometry} material={nodes.Plank.material} /> </Merged> ); }
4. 额外避坑提示
- 确保
instances始终为有效数组,可在Provider中设置默认空数组防止初始未定义:value={{ instances: instances || [] }} - 如果模型加载存在异步延迟,务必通过
loaded状态判断后再渲染Merged,避免因模型未加载导致的异常
内容的提问来源于stack exchange,提问作者Martin Conde
相关产品推荐
相关产品推荐

