useFrame, useThree, useLoaderReact Three Fiber (R3F) provides several powerful hooks that allow you to interact with the Three.js scene and its lifecycle directly within your React components. These hooks simplify common tasks and integrate seamlessly with React's functional component paradigm.
useFrameThe useFrame hook allows you to execute code on every rendered frame. It's the primary way to create animations, update controls, or implement any logic that needs to run continuously as the scene renders. The callback function provided to useFrame receives the current state of the Three.js scene and a delta value (the time elapsed since the last frame), which is useful for creating frame-rate independent animations.
import { useFrame } from '@react-three/fiber';
function AnimatedBox() {
const meshRef = useRef();
useFrame((state, delta) => {
if (meshRef.current) {
meshRef.current.rotation.x += 0.01;
meshRef.current.rotation.y += 0.01;
// You can also use delta for frame-rate independent animation
// meshRef.current.rotation.z += delta * 2;
}
});
return <mesh ref={meshRef}>...</mesh>;
}
useThreeThe useThree hook provides direct access to the core Three.js state model. This state includes essential elements like the default renderer (gl), the scene, the camera, the current size of the canvas, mouse coordinates, and more. It's reactive, meaning if you resize the browser, useThree will provide updated measurements. You can use useThree to dynamically modify the Three.js scene, camera, and renderer within your functional components.
import { useThree } from '@react-three/fiber';
function CameraLogger() {
const { camera, gl, scene } = useThree();
console.log('Camera:', camera);
console.log('Renderer:', gl);
console.log('Scene:', scene);
return null; // This component doesn't render anything visual
}
useLoaderThe useLoader hook is used to load assets (like 3D models, textures, or fonts) and integrates with React's Suspense for easier fallback and error handling. It can take any Three.js loader (e.g., GLTFLoader, OBJLoader, TextureLoader) as its first argument and the URL of the asset as the second. Assets loaded with useLoader are cached by default, using their URLs as cache keys, which allows for efficient re-use of loaded data across your component tree.
import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
function Model() {
const gltf = useLoader(GLTFLoader, 'path/to/your/model.gltf');
return <primitive object={gltf.scene} />;
}
This conceptual example shows how these hooks can be used together within an R3F application. Note that this requires a React environment to run.
import React, { useRef, Suspense } from 'react';
import { Canvas, useFrame, useThree, useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
function SpinningBox() {
const meshRef = useRef();
useFrame(() => {
if (meshRef.current) {
meshRef.current.rotation.x += 0.01;
meshRef.current.rotation.y += 0.01;
}
});
return (
<mesh ref={meshRef}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={'orange'} />
</mesh>
);
}
function SceneContent() {
const { camera } = useThree();
// You can manipulate the camera here, for example
// camera.position.z = 5;
// Example of loading a model (replace with a valid path if you want to test)
// const gltf = useLoader(GLTFLoader, 'path/to/your/model.gltf');
return (
<>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<SpinningBox position={[-1.2, 0, 0]} />
<SpinningBox position={[1.2, 0, 0]} />
{/* <primitive object={gltf.scene} /> */}
</>
);
}
export default function App() {
return (
<Canvas>
<Suspense fallback={null}>
<SceneContent />
</Suspense>
</Canvas>
);
}