React Three Fiber (R3F) leverages React's component-based architecture to create and manage Three.js scenes, making it easy to build reusable 3D components and manage their properties using props.
In R3F, you define 3D objects and their behaviors as standard React components. This allows you to encapsulate Three.js logic, state, and interactions within self-contained units that can be reused throughout your application.
For example, instead of manually creating a THREE.Mesh and its geometry and material in imperative Three.js code, you can define a Box component that renders a mesh with a box geometry and a standard material. This component can then be instantiated multiple times with different properties.
Props in R3F function identically to props in standard React. They are used to pass data and attributes from a parent component to a child component, allowing you to customize instances of your reusable 3D components.
position, scale, rotation, color, intensity for lights, etc.) can be passed directly as props to their corresponding JSX elements. R3F automatically maps these props to the underlying Three.js object's properties.args prop): For Three.js objects that require arguments during their instantiation (e.g., new THREE.BoxGeometry(width, height, depth)), R3F uses a special args prop. This prop accepts an array of values that are passed directly to the Three.js constructor.Here's a simple example of a reusable Box component that accepts position, color, and rotationSpeed as props. Note that this requires a React environment to run.
import React, { useRef, useState } from 'react';
import { Canvas } from '@react-three/fiber';
// Reusable Box component
function Box(props) {
const meshRef = useRef();
const [hovered, setHover] = useState(false);
const [active, setActive] = useState(false);
useFrame((state, delta) => {
if (meshRef.current) {
meshRef.current.rotation.x += delta * (props.rotationSpeed || 1);
meshRef.current.rotation.y += delta * (props.rotationSpeed || 1);
}
});
return (
<mesh
{...props} // Spread all other props (like position) onto the mesh
ref={meshRef}
scale={active ? [1.5, 1.5, 1.5] : [1, 1, 1]}
onClick={() => setActive(!active)}
onPointerOver={() => setHover(true)}
onPointerOut={() => setHover(false)}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : props.color} />
</mesh>
);
}
// App component using the reusable Box
export default function App() {
return (
<Canvas>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} color="orange" rotationSpeed={2} />
<Box position={[1.2, 0, 0]} color="purple" rotationSpeed={0.5} />
</Canvas>
);
}