使用react-three-drei的View结合Routes时OrbitControls失效问题
路由切换后react-three-drei View组件的OrbitControls失效解决方案
问题根源
当前实现中,路由切换时页面内被View追踪的DOM元素(canvasView1、canvasView2)会被销毁重建,而<View>的track引用未同步更新,同时两个<OrbitControls>都设置了makeDefault,导致事件监听冲突,最终引发操控失效。
具体修复步骤
1. 移除多个OrbitControls的makeDefault属性
同一个Canvas下多个控件设置makeDefault会抢占事件绑定权限,直接去掉该属性:
// App.js 中修改两个OrbitControls <OrbitControls />
2. 动态同步View的track引用
路由切换后,页面内的DOM元素是全新创建的,需要将ref同步到状态中,确保<View>能获取最新的DOM节点:
// 在App.js中添加状态和监听 import { useLocation } from 'react-router-dom'; import { useState, useEffect, useRef } from 'react'; export default function App() { const [canvasWrapperRef, canvasView1, canvasView2] = useRefs(); const canvasRefs = { canvasView1, canvasView2 }; const location = useLocation(); const [view1Ref, setView1Ref] = useState(null); const [view2Ref, setView2Ref] = useState(null); const canvasStateRef = useRef(null); // 路由切换时同步最新的DOM引用并重新绑定事件 useEffect(() => { setView1Ref(canvasView1.current); setView2Ref(canvasView2.current); if (canvasStateRef.current) { canvasStateRef.current.events.connect(canvasWrapperRef.current); } }, [location]); return ( <div className="App"> <div ref={canvasWrapperRef}> <Suspense fallback={null}> <Routes> <Route path="/" element={<Homepage ref={canvasRefs} />} /> <Route path="/other" element={<OtherPage ref={canvasRefs} />} /> </Routes> <Canvas onCreated={(state) => { canvasStateRef.current = state; state.events.connect(canvasWrapperRef.current); }} className="canvas" > {/* 使用状态中的ref而非原始useRefs */} <View track={view1Ref}> <Scene /> <TransformControls> <Soda scale={6} position={[0, -1.6, 0]} /> </TransformControls> <OrbitControls enabled={location.pathname === '/'} /> </View> <View track={view2Ref}> <color attach="background" args={["lightblue"]} /> <Scene /> <TransformControls position={[0, -1, 0]}> <Duck scale={2} position={[0, -1.6, 0]} /> </TransformControls> <OrbitControls enabled={location.pathname === '/other'} /> </View> <Preload all /> </Canvas> </Suspense> </div> </div> ); }
3. 按需启用OrbitControls
通过enabled属性,让每个路由页面只激活对应的控件,避免不必要的事件冲突:
- 首页仅启用第一个View的OrbitControls
- 其他页面仅启用第二个View的OrbitControls
关键说明
- 路由切换会触发页面组件卸载重建,因此
track绑定的DOM节点会变化,必须同步更新View的引用 - Canvas事件系统需要在路由切换后重新绑定,确保鼠标事件能正确传递到Canvas
- 多个OrbitControls共存时,必须避免同时设置
makeDefault,改用enabled属性控制激活状态
内容的提问来源于stack exchange,提问作者Monstar
相关产品推荐
相关产品推荐

