Building Interactive 3D Experiences with React Three Fiber

Anthony Coffey
Category: Web Development

Three.js has transformed how developers create 3D content for the web, but integrating it with modern React applications has traditionally been complex. Enter React Three Fiber – a React renderer for Three.js that brings a declarative, component-based approach to 3D graphics development.

Table of Contents

Introduction to React Three Fiber

React Three Fiber (R3F) is a React renderer for Three.js that allows you to create 3D scenes using React's component-based architecture. It bridges the gap between React's declarative programming model and Three.js's imperative 3D graphics API.

Why Use React Three Fiber?

  1. Declarative Syntax: Define 3D scenes using JSX for better readability and maintainability
  2. React Integration: Seamlessly blend 3D elements with your React application
  3. Reconciliation: Automatic handling of scene graph updates
  4. Hooks: Use React hooks for animations, interactions, and state management
  5. Ecosystem: Access to a growing collection of tools and extensions like drei

Example Scene

Inspired by Pink Floyd's "Wish You Were Here", I "vibe coded" a simple Fishbowl scene for this article. No imported models, the entire scene was generated with code using React Fiber.

View Source on CodeSandbox

How I wish, how I wish you were here,
We're just two lost souls swimming in a fishbowl, year after year.
Runnin' over the same old ground, what have we found?
the same old fears, wish you were here …

Interactive Scene Example

This example shows two simple 3D shapes that rotate continuously. Click on a shape to increase its size, or click and drag to control the camera.

Core Concepts

React Three Fiber translates React components into Three.js objects:

// React Three Fiber component
<mesh position={[0, 0, 0]}>
  <boxGeometry args={[1, 1, 1]} />
  <meshStandardMaterial color="hotpink" />
</mesh>;

// Equivalent Three.js code
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 'hotpink' });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, 0);
scene.add(mesh);

Getting Started with React Three Fiber

Installation

To get started with React Three Fiber, you'll need to install the necessary packages:

npm install three @react-three/fiber @react-three/drei

Basic Setup

Creating a 3D scene requires a canvas element where Three.js can render:

import { Canvas } from '@react-three/fiber';

function App() {
  return (
    <Canvas>
      <ambientLight intensity={0.5} />
      <pointLight position={[10, 10, 10]} />
      <mesh>
        <boxGeometry />
        <meshStandardMaterial color="orange" />
      </mesh>
    </Canvas>
  );
}

The Canvas component sets up the Three.js renderer, scene, and camera, providing a foundation for your 3D content.

Creating Basic 3D Elements

Primitives

React Three Fiber provides primitives that map directly to Three.js objects:

// Basic shapes
<mesh>
  <boxGeometry args={[1, 1, 1]} />
  <meshStandardMaterial color="red" />
</mesh>

<mesh position={[2, 0, 0]}>
  <sphereGeometry args={[0.5, 32, 32]} />
  <meshStandardMaterial color="blue" />
</mesh>

<mesh position={[-2, 0, 0]}>
  <cylinderGeometry args={[0.5, 0.5, 1, 32]} />
  <meshStandardMaterial color="green" />
</mesh>

Positioning and Transformations

You can position and transform objects using props:

<mesh
  position={[x, y, z]}
  rotation={[rotX, rotY, rotZ]}
  scale={[scaleX, scaleY, scaleZ]}
>
  {/* geometry and material */}
</mesh>

Animations and Interactions

React Three Fiber provides hooks for creating animations and handling interactions.

useFrame for Animations

The useFrame hook gives you access to the animation loop:

import { useFrame } from '@react-three/fiber';
import { useRef } from 'react';

function RotatingBox() {
  const meshRef = useRef();

  useFrame((state, delta) => {
    meshRef.current.rotation.x += delta;
    meshRef.current.rotation.y += delta * 0.5;
  });

  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshNormalMaterial />
    </mesh>
  );
}

Handling Interactions

You can use standard React event handlers for interactions:

function InteractiveCube() {
  const [active, setActive] = useState(false);
  const [hovered, setHovered] = useState(false);

  return (
    <mesh
      onClick={() => setActive(!active)}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
      scale={active ? 1.5 : 1}
    >
      <boxGeometry />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  );
}

Lighting and Materials

Lighting

React Three Fiber provides components for various light types:

<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} intensity={1} />
<directionalLight position={[0, 5, 5]} intensity={1.5} castShadow />
<spotLight position={[0, 5, 0]} angle={0.3} penumbra={1} intensity={2} castShadow />

Materials

You can use any Three.js material:

// Basic material
<meshBasicMaterial color="red" wireframe />

// Standard material (with light reactions)
<meshStandardMaterial
  color="blue"
  roughness={0.5}
  metalness={0.5}
/>

// Physical material (more parameters)
<meshPhysicalMaterial
  color="green"
  roughness={0.1}
  metalness={0.8}
  clearcoat={1}
  clearcoatRoughness={0.2}
/>

Camera Controls

The @react-three/drei package provides helpful controls:

import { OrbitControls } from '@react-three/drei';

function Scene() {
  return (
    <Canvas>
      <OrbitControls enableZoom={true} enablePan={true} enableRotate={true} />
      {/* Your 3D objects */}
    </Canvas>
  );
}

Other camera controls include:

  • TrackballControls
  • FlyControls
  • PointerLockControls
  • FirstPersonControls

Performance Optimization

Instance Meshes

For rendering many similar objects:

import { Instance, Instances } from '@react-three/drei';

function ManyBoxes() {
  return (
    <Instances limit={1000}>
      <boxGeometry />
      <meshStandardMaterial color="red" />
      {Array.from({ length: 100 }, (_, i) => (
        <Instance
          key={i}
          position={[
            Math.random() * 10 - 5,
            Math.random() * 10 - 5,
            Math.random() * 10 - 5,
          ]}
        />
      ))}
    </Instances>
  );
}

Using the useMemo Hook

Optimize geometry and material creation:

function OptimizedBoxes() {
  const geometry = useMemo(() => new THREE.BoxGeometry(1, 1, 1), []);
  const material = useMemo(
    () => new THREE.MeshStandardMaterial({ color: 'hotpink' }),
    [],
  );

  return (
    <>
      <mesh geometry={geometry} material={material} position={[0, 0, 0]} />
      <mesh geometry={geometry} material={material} position={[2, 0, 0]} />
      <mesh geometry={geometry} material={material} position={[-2, 0, 0]} />
    </>
  );
}

Advanced Techniques

Post-Processing Effects

Using the @react-three/postprocessing package:

import {
  EffectComposer,
  Bloom,
  ChromaticAberration,
} from '@react-three/postprocessing';

function Scene() {
  return (
    <Canvas>
      {/* Your 3D objects */}
      <EffectComposer>
        <Bloom intensity={1.0} luminanceThreshold={0.5} />
        <ChromaticAberration offset={[0.005, 0.005]} />
      </EffectComposer>
    </Canvas>
  );
}

Loading 3D Models

You can load 3D models using the useLoader hook:

import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

function Model() {
  const gltf = useLoader(GLTFLoader, '/path/to/model.gltf');

  return (
    <primitive object={gltf.scene} position={[0, 0, 0]} scale={[1, 1, 1]} />
  );
}

Or with the simplified useGLTF hook from drei:

import { useGLTF } from '@react-three/drei';

function Model() {
  const { scene } = useGLTF('/path/to/model.gltf');

  return <primitive object={scene} />;
}

Conclusion

React Three Fiber brings the power of Three.js to React applications in an elegant, declarative way. By leveraging React's component model and state management, it makes 3D web development more accessible and maintainable.

Here's a recap of the key benefits:

  1. Declarative approach to 3D scenes using familiar React patterns
  2. Simplified state management using React hooks and context
  3. Automatic optimization through React's reconciliation
  4. Seamless integration with your React application
  5. Rich ecosystem of helpers and extensions

Whether you're building immersive product configurators, data visualizations, games, or artistic experiences, React Three Fiber provides a solid foundation for creating compelling 3D content on the web.

Next Steps

To continue learning about React Three Fiber:

  1. Explore more complex animations using react-spring
  2. Learn about physics simulations with @react-three/cannon
  3. Dive into shaders for custom visual effects
  4. Experiment with VR and AR using @react-three/xr

The combination of React's component model with Three.js's rendering capabilities opens up endless possibilities for creating engaging 3D experiences on the web.