React-Three-Fiber路由切换时Canvas不更新残留3D模型问题
解决方案
问题本质
你的Canvas挂载在路由体系外部,里面的<View>和torus组件不会随路由切换自动卸载。即使Home组件卸载后splashView的ref变为null,react-three-fiber也不会自动销毁这些3D元素,导致残留显示。
可行方案:路由驱动的条件渲染
通过监听当前路由,仅在首页路径下渲染3D内容,利用React的声明式渲染自动处理组件卸载与3D资源清理。
步骤1:导入路由状态钩子
在组件顶部导入useLocation:
import { useLocation } from 'react-router-dom';
步骤2:监听当前路由
在组件内部获取当前路由信息:
const location = useLocation();
步骤3:条件渲染3D内容
修改Canvas内的代码,仅当路由为首页时渲染torus相关组件:
<Canvas eventSource={ref} className={styles.canvas}> {/* 仅在首页且Home组件已挂载时渲染3D元素 */} {(['/', '/home'].includes(location.pathname) && splashView.current) && ( <View track={splashView}> <ambientLight intensity={0.1} /> <directionalLight color="red" position={[0, 0, 5]} /> <mesh> <torusGeometry/> <meshStandardMaterial /> </mesh> </View> )} </Canvas>
完整修改后的代码示例
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom'; import { Canvas, View } from '@react-three/fiber'; import { useRef, forwardRef } from 'react'; import Navbar from './Navbar'; import Syllabus from './Syllabus'; // 已通过forwardRef处理的Home组件 const Home = forwardRef((props, ref) => { return <div ref={ref}>首页内容</div>; }); export default function App() { const ref = useRef(); const splashView = useRef(); const location = useLocation(); return ( <div> <BrowserRouter> <div ref={ref}> <Navbar/> <Routes> <Route index element={<Home ref={splashView}/>}/> <Route path="/home" element={<Home ref={splashView}/>}/> <Route path="/syllabus" element={<Syllabus/>}/> </Routes> </div> </BrowserRouter> <Canvas eventSource={ref} className={styles.canvas}> {(['/', '/home'].includes(location.pathname) && splashView.current) && ( <View track={splashView}> <ambientLight intensity={0.1} /> <directionalLight color="red" position={[0, 0, 5]} /> <mesh> <torusGeometry/> <meshStandardMaterial /> </mesh> </View> )} </Canvas> </div> ); }
原理说明
- 当路由切换出首页时,条件渲染的表达式返回
false,<View>及其子组件会被React卸载。 - react-three-fiber会自动处理卸载时的Three.js资源清理,无需手动操作。
- 额外判断
splashView.current是为了确保Home组件已完成DOM挂载,避免<View>跟踪不存在的元素。
内容的提问来源于stack exchange,提问作者Cookie
相关产品推荐
相关产品推荐

