This example shows how to use animate a cube and highly reuse each part of Three.js.
import * as React from "react";
import * as THREE from "three";
// WORLD SIZE
// ---
const defineWorldSize = (renderer) => {
renderer.setSize(window.innerWidth, window.innerHeight);
};
// WORLD RESIZE
// ---
const useWorldResizer = ({ renderer, camera }) => {
const resizer = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
defineWorldSize(renderer);
};
window.addEventListener("resize", resizer, false);
};
// WORLD CREATION
// ---
const useWorld = () => {
// RENDERER
// ---
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor("#ffffff");
// SCENE
// ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xcccccc);
// scene.fog = new THREE.Fog(0x000000, 4, 12);
// CAMERA
// ---
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 8);
// LIGHT
// ---
const light = new THREE.PointLight(0xffffff, 2, 0, 2);
light.position.set(100, 100, 100);
scene.add(light);
return { renderer, scene, camera };
};
// OBJECT CUBE
// ---
const useDemoCube = (scene) => {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0xff385c });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
return { cube };
};
// ANIMATION ROTATION
// ---
const animationRotation = (obj) => {
(obj.rotation || {}).x += 0.01;
(obj.rotation || {}).y += 0.01;
};
// ANIMATION RENDER
// --
const animationRender = (animation, loadedRenderer, requestRef) => {
animation();
if (typeof loadedRenderer === "function") loadedRenderer();
const renderedAnimation = () => animationRender(animation, loadedRenderer, requestRef);
const frameId = requestAnimationFrame(renderedAnimation);
requestRef.current = frameId;
};
const animationStop = (requestRef) => {
cancelAnimationFrame(requestRef.current);
};
const useThree = (threeRef, requestRef) => {
// Get our renderer and other elements of our world
const { renderer, scene, camera } = useWorld();
// Define the size of our 3D world$
defineWorldSize(renderer);
// Use the resizer, for when our window gets resized
useWorldResizer({ renderer, camera });
// Create a simple cube
const { cube } = useDemoCube(scene);
// Define our animation
const animation = () => animationRotation(cube);
// Define our renderer
const loadedRenderer = () => renderer.render(scene, camera);
// Render our animation
animationRender(animation, loadedRenderer, requestRef);
// Append our renderer to the DOM
threeRef.current.append(renderer.domElement);
};
const ThreeComponent = () => {
const threeRef = React.useRef(null);
// * DO NOT USE useState to get the frameId - https://css-tricks.com/using-requestanimationframe-with-react-hooks/
const requestRef = React.useRef();
React.useEffect(() => {
useThree(threeRef, requestRef);
return () => animationStop(requestRef);
}, []);
return <div ref={threeRef} />;
};
export default ThreeComponent;