To understand what React Three Fiber (R3F) is and what it means to integrate 3D declaratively, we must first contrast it with the traditional (imperative) way of using Three.js.
Imperative vs Declarative
1. The Imperative Approach (Vanilla Three.js)
In imperative programming, you tell the computer HOW to perform every exact step. To create a simple red cube in pure Three.js, you have to write manual step-by-step code: instantiate the scene, camera, renderer, geometry, material, mesh, append it to the scene, and set up an animation loop.
The resulting code tends to be lengthy and difficult to integrate cleanly into modern reactive data flows (like React state).
2. The Declarative Approach (React Three Fiber)
With React Three Fiber, we move to a declarative approach. Instead of step-by-step mathematical instructions, you build your 3D scene using components—just like building a button or form in HTML/JSX. You define WHAT you want, and the library handles the underlying instantiation and updates.
import { Canvas } from '@react-three/fiber'
import { Suspense } from 'react'
export function Scene3D({ selectedColor }) {
return (
<Canvas>
<ambientLight intensity={1.2} />
<directionalLight position={[10, 10, 5]} intensity={2} />
<Suspense fallback={null}>
{/* 3D components naturally respond to React state */}
<ModelFactory url="/models/t-shirt.obj" color={selectedColor} />
</Suspense>
</Canvas>
)
}Advantages of the Declarative Approach in 3D
- Component Reusability: Encapsulate lights, models, and interactions into standard React components and reuse them anywhere across your application.
- Built-in Reactivity: 3D properties (position, scale, material color) can bind directly to React state (
useState,Context, Zustand, etc.). When state updates, the 3D model re-renders automatically. - Lifecycle Management: R3F automatically handles memory allocation and disposal when components mount or unmount, preventing common memory leaks found in Vanilla Three.js.