@react-three/fiber场景卸载报错及directionalLight弃用属性警告问题求助
问题背景
我正在开发一个@react-three/fiber 3D场景,遇到两个问题:
- 第一个问题和
directionalLight相关:当我尝试使用新版three.js的属性比如shadow.camera.far配置灯光时,@react-three/fiber无法正常调用灯光阴影的dispose方法,因此只能使用已弃用的旧属性,导致控制台出现大量警告。 - 核心问题:给场景中的3D模型绑定了点击跳转页面的逻辑,触发跳转时会抛出@react-three/fiber错误
Uncaught TypeError: Cannot read property 'disconnect' of undefined。推测是因为在scene的useEffect清理函数中调用了unmountComponentAtNode方法,导致组件在@react-three/fiber完全移除所有three.js对象前就提前卸载了。但如果删掉这个方法,又会出现React报错:Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function。
解决方案
1. DirectionalLight废弃属性警告修复
按@react-three/fiber的嵌套属性规范写配置即可,不需要使用扁平的废弃属性,写法参考:
<directionalLight position={[-3, 5, 5]} color='#ffffff' intensity={3} castShadow shadow-bias={0.05} shadow-mapSize-height={1024} shadow-mapSize-width={1024} > <orthographicCamera attach='shadow-camera' far={15} /> </directionalLight>
@react-three/fiber支持短横线属性名映射到嵌套对象属性,也支持attach属性直接绑定到父元素的对应子对象上,这种写法既适配新版three.js API,也不会触发dispose异常。
2. 跳转报错+未挂载组件更新警告修复
错误根源有两个:
- 手动调用
unmountComponentAtNode卸载canvas节点,和@react-three/fiber自身的卸载逻辑冲突,导致框架清理内部资源时找不到对应对象抛出disconnect错误 - 点击跳转后
setRedirectPath触发重渲染,页面跳转组件卸载后,Model组件内的setTimeout异步逻辑还在执行,导致状态更新警告
具体修改步骤:
- 直接删除
Scene组件useEffect清理函数中的unmountComponentAtNode调用,Canvas组件自带完整的资源清理逻辑,不需要手动卸载 - 给异步逻辑加卸载标记,避免组件卸载后执行状态更新:
const Model = ({ changePage }) => { const isUnmounted = useRef(false) // 原有其他ref声明保留 useEffect(() => { return () => { isUnmounted.current = true } }, []) // 修改handlePointerUp内的setTimeout逻辑 const handlePointerUp = () => { if (active.current) { setTimeout(() => { if (isUnmounted.current) return moving.current = false active.current = false }, 30) } } // 其余原有代码保留 }
- 给Scene组件的跳转逻辑加卸载判断:
const Scene = () => { const [redirectPath, setRedirectPath] = useState('') const isUnmounted = useRef(false) useEffect(() => { return () => { isUnmounted.current = true } }, []) useEffect(() => { if (redirectPath && !isUnmounted.current) { window.appHistory.push(redirectPath) } }, [redirectPath]) // 其余原有代码保留,去掉清理函数内的unmountComponentAtNode调用 }
内容的提问来源于stack exchange,提问作者isaacsan 123
相关产品推荐
相关产品推荐

