React-Vite-TS项目中useEffect内Three.js初始化函数执行两次问题
问题原因
这是Vite+React开发环境下的**React严格模式(Strict Mode)**导致的。React在开发模式下的Strict Mode会刻意重复执行一些生命周期函数和副作用(包括空依赖的useEffect),目的是帮你提前检测代码中可能存在的副作用泄漏问题——比如未清理的定时器、重复订阅等。而生产环境(npm run build后)Strict Mode会自动禁用,所以不会出现重复调用的情况。
修复方案
方法1:临时关闭React Strict Mode
在项目入口文件(通常是src/main.tsx)中,找到包裹App的<StrictMode>标签并移除,开发环境下就不会重复执行useEffect了:
// 移除前 ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <App /> </React.StrictMode>, ); // 移除后 ReactDOM.createRoot(document.getElementById('root')!).render( <App />, );
方法2:给Three.js初始化逻辑加防重复判断
如果不想关闭Strict Mode(毕竟它能帮你排查潜在问题),可以在initThreeProcess函数里加一层判断,确保渲染器DOM元素只被插入一次:
function initThreeProcess(container: HTMLElement) { // 检查容器内是否已有渲染器元素,有则直接返回 if (container.querySelector('.webgl-renderer')) return; // 你的Three.js初始化逻辑 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.domElement.classList.add('webgl-renderer'); // 标记类名用于判断 container.appendChild(renderer.domElement); // VR按钮、3D物体添加等后续逻辑... }
方法3:用useRef标记初始化状态
在组件内通过useRef记录是否已经完成初始化,避免useEffect重复执行逻辑:
import { useEffect, useRef } from 'react'; const ThreeCanvasContainer = () => { const containerRef = useRef<HTMLDivElement>(null); const hasInitialized = useRef(false); useEffect(() => { if (!containerRef.current || hasInitialized.current) return; initThreeProcess(containerRef.current); hasInitialized.current = true; }, []); return <div ref={containerRef}></div>; };
内容的提问来源于stack exchange,提问作者XxTavo16xX
相关产品推荐
相关产品推荐

