React-Three-Fiber | How three.js is used with React.js – Introduction

Total
0
Shares
react-three-fiber introduction

Three.js is the 3d animation library which is used to design games, movies, scenes, animations, graphics, vfx etc. If you want to learn more about three.js then follow our introductory guide –

In this article, we will learn about react-three-fiber which is a react renderer for three.js. According to official page

React-three-fiber is required for react developers because you can build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can tap into React’s ecosystem.

Introduction

React-three-fiber is the react renderer for three.js. It means that all the functionality of three.js is supported in this library. It doesn’t depend on any particular version of three.js. So, overall there are no limitations and no performance lag.

To install react-three-fiber, use npm –

npm install three @react-three/fiber

You should create your project using create-react-app.

Prerequisite

  1. You should have a basic understanding of three.js. You may learn the introduction and fundamentals from this guide.
  2. Be aware of React coding. This whole blog is filled with react articles, but you may refer official documentation.

Three.js Vs React-three-fiber

In this section, we will look at the differences between three.js and React-three-fiber. We need to understand how something in three.js could be done in react-three-fiber.

As we have discussed in our three.js guide, there are three main entities for creating an animation –

  1. Scene
  2. Camera
  3. Renderer

Let’s see three.js code first and then we will check out the equivalent react-three-fiber code –

<script>
  const scene = new THREE.Scene();

  const geometry = new THREE.BoxGeometry();
  const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
  const cube = new THREE.Mesh( geometry, material );

  scene.add( cube );

  const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  camera.position.z = 5;

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  const animate = function () {
    requestAnimationFrame( animate );

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render( scene, camera );
  };

  animate();
</script>

Here we have scene, box geometry, camera, renderer and animation loop.

In react-three-fiber, we have Canvas, mesh and useFrame() hook. Let’s see their functions and how they are used –

<Canvas>

<Canvas> is the component provided by react-three-fiber which handles the scene, camera and auto re-rendering. So, a single <Canvas> code could handle this much of three.js code –

<script>
  const scene = new THREE.Scene();

  // const geometry = new THREE.BoxGeometry();
  // const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
  // const cube = new THREE.Mesh( geometry, material );

  // scene.add( cube );

  const camera = new THREE.PerspectiveCamera( 75, parentDivWidth / parentDivHeight, 0.1, 1000 );
  // camera.position.z = 5;

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize( parentDivWidth, parentDivHeight );
  document.querySelector('#canvas-container').appendChild( renderer.domElement );

  const animate = function () {
    requestAnimationFrame( animate );

    // cube.rotation.x += 0.01;
    // cube.rotation.y += 0.01;

    renderer.render( scene, camera );
  };

  animate();
</script>

Here is the equivalent react-three-fiber code –

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

export default function App() {
  return (
    <div id="canvas-container">
      <Canvas />
    </div>
  )
}

If you want to change the width or height of canvas, then change the size of parent container, i.e. #canvas-container. The Canvas will automatically resize.

Since Canvas component handles both scene and camera, so there are few props which could come handy in setting properties like camera fov, aspect ratio, far clip etc. This below table will help you in setting Canvas options –

PROP DESCRIPTION DEFAULT
children Threejs jsx elements or regular components
gl Props that go into the default renderer, or your own renderer {}
camera Props that go into the default camera, or your own THREE.Camera { fov: 75, near: 0.1, far: 1000, position: [0, 0, 5] }
shadows Props that go into gl.shadowMap, can also be set true for PCFsoft false
raycaster Props that go into the default raycaster {}
vr Switches renderer to VR mode, then uses gl.setAnimationLoop false
mode React mode: legacy, blocking, concurrent blocking
resize Resize config, see react-use-measure’s options { scroll: true, debounce: { scroll: 50, resize: 0 } }
orthographic Creates an orthographic camera false
dpr Pixel-ratio, use window.devicePixelRatio, or automatic: [min, max] undefined
linear Switch off automatic sRGB encoding and gamma correction false
flat Use THREE.NoToneMapping instead of THREE.ACESFilmicToneMapping false
onCreated Callback after the canvas has rendered (but not yet committed) (state) => {}
onPointerMissed Response for pointer clicks that have missed any target (event) => {}

<mesh>

This component holds the geometries and materials. Like in three.js, we create geometry, material and a mesh, here we have components for all of them. Suppose our three.js code is –

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const cube = new THREE.Mesh( geometry, material );

The equivalent code in react-three-fiber is –

<mesh>
  <boxGeometry />
  <meshBasicMaterial color={"#ff0000"} />
</mesh>
  • THREE.Mesh is represented by <mesh> component.
  • Three.BoxGeometry is represented by <boxGeometry /> component.
  • Three.MeshBasicMaterial is represented by <meshBasicMaterial /> component.

To include the mesh in the scene, three.js code is –

scene.add( cube );

But in react library, we put the <mesh> component as child of <Canvas> component.

<Canvas>
  <mesh>
    <boxGeometry />
    <meshBasicMaterial color={"#ff0000"} />
  </mesh>
</Canvas>

You can have any number of mesh objects within your canvas.

useFrame()

To run an animation loop, three.js uses requestAnimationFrame function. The same could be achieved using useFrame() hook in react-three-fiber. Note: Fiber hooks can only be called inside a <Canvas> parent so you need to call it from a separate component.

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

const AnimateFrame = (props) => {
  useFrame(({ clock }) => {
    props.meshRef.current.rotation.x += 0.01;
  });
  return null;
}

export default function App() {

  const myMesh = React.useRef();

  return (
    <div id="canvas-container">
      <Canvas>
        <mesh ref={myMesh}>
          <boxGeometry />
          <meshBasicMaterial color={"#ff0000"} />
        </mesh>
        <AnimateFrame meshRef={myMesh} />
      </Canvas>
    </div>
  )
}

Here we have created a ref variable, myMesh which is passed as ref prop in <mesh>. To play animation using useFrame(), we created a different component, AnimateFrame. Then, we included this component as a child of <Canvas> and passed myMesh as prop because we want to rotate mesh object and for that we need our <mesh> reference in AnimateFrame.

    Tweet this to help others

Live Demo

Open Live Demo