如何在React项目中无window对象优雅组织Three.js相关导入?
Great questions—let’s fix your setup to be more maintainable and let you reuse that Three.js example code almost verbatim.
1. Replace Global Scripts with Modular npm Imports
The global script approach works, but it’s messy and goes against React’s component-based, modular workflow. Here’s how to clean it up:
Step 1: Install Dependencies
First, remove those <script> tags from index.html, then install all required packages via npm:
# Core Three.js library (includes most controls now!) npm install three # Optional but recommended: TypeScript types for better IDE support npm install @types/three --save-dev # For stats.js and dat.gui (used in the spline editor example) npm install stats.js dat.gui
Step 2: Import Directly in Your React Component
Now you can import everything you need directly in your 3DComponent instead of relying on global window variables:
import * as THREE from 'three'; // Import controls from Three.js's official addons (previously examples/js) import { OrbitControls, TransformControls, DragControls } from 'three/addons/controls/index.js'; import Stats from 'stats.js'; import * as dat from 'dat.gui';
This keeps all dependencies scoped to your component and avoids polluting the global namespace.
2. Ditch window.THREE and Reuse Example Code
With modular imports, you can write code exactly like the Three.js spline editor example—no more window. prefixes needed.
Before (Global Scripts):
const controls = new window.THREE.OrbitControls(camera, renderer.domElement); const clock = new window.THREE.Clock();
After (Modular Imports):
// OrbitControls is imported directly, so no THREE. prefix needed for it const controls = new OrbitControls(camera, renderer.domElement); // Clock is part of the core THREE module, so use THREE.Clock() const clock = new THREE.Clock();
Pro Tip: Manage Scene/Camera with React Refs
The Three.js example uses global variables for objects like scene, camera, and renderer—in React, you’ll want to use useRef to keep track of these instances without polluting the global scope. Here’s a quick template:
import { useRef, useEffect } from 'react'; import * as THREE from 'three'; import { OrbitControls, TransformControls, DragControls } from 'three/addons/controls/index.js'; import Stats from 'stats.js'; import * as dat from 'dat.gui'; function ThreeDSplineEditor() { const containerRef = useRef(null); const sceneRef = useRef(null); const cameraRef = useRef(null); const rendererRef = useRef(null); useEffect(() => { if (!containerRef.current) return; // 1. Copy-paste scene setup from the spline editor example here const scene = new THREE.Scene(); sceneRef.current = scene; const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); cameraRef.current = camera; const renderer = new THREE.WebGLRenderer(); renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight); containerRef.current.appendChild(renderer.domElement); rendererRef.current = renderer; // 2. Add controls, spline logic, stats, dat.gui exactly like the example const controls = new OrbitControls(camera, renderer.domElement); const transformControls = new TransformControls(camera, renderer.domElement); // ... rest of the example code ... // 3. Animation loop const animate = () => { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); }; animate(); // Cleanup when component unmounts return () => { containerRef.current?.removeChild(renderer.domElement); renderer.dispose(); }; }, []); return <div ref={containerRef} style={{ width: '100%', height: '100vh' }} />; } export default ThreeDSplineEditor;
You can now paste almost all of the spline editor example’s code into the useEffect hook—just adjust any global variable references to use your useRef instances instead.
内容的提问来源于stack exchange,提问作者ivan

