React Three Fiber纹理加载报错:组件响应同步输入时挂起求助
解决React Three Fiber加载纹理时的Suspend错误
错误原因
React 18的并发模式下,当组件在响应同步输入操作(比如点击、表单输入)时触发异步加载(纹理加载属于异步操作),组件会进入suspend状态,此时React会抛出该错误,提示你需要明确处理这种可延迟的更新。
解决方案
1. 用React.Suspense包裹纹理组件
如果是组件初始化时就加载纹理,直接用Suspense包裹使用纹理的组件,指定加载时的 fallback 内容即可:
// 父组件/App.jsx import { Suspense } from 'react'; import { Canvas } from '@react-three/fiber'; import TexturedPlane from './TexturedPlane'; export default function App() { return ( <Canvas> {/* 用Suspense包裹,加载时显示灰色立方体作为占位 */} <Suspense fallback={<mesh><boxGeometry /><meshBasicMaterial color="#888" /></mesh>}> <TexturedPlane /> </Suspense> </Canvas> ); }
// TexturedPlane.jsx import { useTexture } from '@react-three/drei'; export default function TexturedPlane() { // 正常使用useTexture加载纹理 const texture = useTexture('/textures/texture.png'); return ( <mesh position={[0,0,0]}> <planeGeometry args={[5,5]} /> <meshBasicMaterial map={texture} /> </mesh> ); }
2. 用startTransition包裹输入触发的加载逻辑
如果纹理加载是由用户输入(比如点击按钮)触发的,需要把加载操作包裹在startTransition中,告诉React这个更新可以延迟执行:
import { useState, startTransition } from 'react'; import { useTexture } from '@react-three/drei'; export default function TextureLoader() { const [texture, setTexture] = useState(null); const handleLoad = () => { // 把加载逻辑放在startTransition内 startTransition(() => { const loadedTexture = useTexture('/textures/texture.png'); setTexture(loadedTexture); }); }; return ( <> <button onClick={handleLoad}>加载纹理</button> {texture && ( <mesh> <planeGeometry args={[3,3]} /> <meshBasicMaterial map={texture} /> </mesh> )} </> ); }
3. 预加载纹理(可选)
如果希望纹理在应用启动时就加载完成,可以在应用初始化阶段预加载,避免后续操作触发suspend:
// 在App初始化时预加载 import { TextureLoader } from 'three'; import { useEffect, useState } from 'react'; import { Canvas } from '@react-three/fiber'; export default function App() { const [preloadedTexture, setPreloadedTexture] = useState(null); useEffect(() => { const loader = new TextureLoader(); loader.load('/textures/texture.png', (texture) => { setPreloadedTexture(texture); }); }, []); if (!preloadedTexture) return <div>加载中...</div>; return ( <Canvas> <mesh> <planeGeometry /> <meshBasicMaterial map={preloadedTexture} /> </mesh> </Canvas> ); }
内容的提问来源于stack exchange,提问作者Sisandy
相关产品推荐
相关产品推荐

