What is @react-three/fiber?
@react-three/fiber is a React renderer for Three.js, enabling the creation of 3D graphics and animations using React components. It simplifies the process of integrating Three.js with React, allowing developers to leverage React's declarative approach to build complex 3D scenes.
What are @react-three/fiber's main functionalities?
Creating a Basic 3D Scene
This code demonstrates how to create a basic 3D scene with two boxes using @react-three/fiber. The `Canvas` component sets up the 3D rendering context, and the `Box` component from `@react-three/drei` is used to add 3D objects to the scene.
```jsx
import React from 'react';
import { Canvas } from '@react-three/fiber';
import { Box } from '@react-three/drei';
function App() {
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>
);
}
export default App;
```
Animating Objects
This code shows how to animate a 3D object using @react-three/fiber. The `useFrame` hook is used to update the rotation of the box on every frame, creating a continuous animation.
```jsx
import React, { useRef } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
function RotatingBox() {
const mesh = useRef();
useFrame(() => (mesh.current.rotation.x = mesh.current.rotation.y += 0.01));
return (
<mesh ref={mesh}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={'orange'} />
</mesh>
);
}
function App() {
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<RotatingBox />
</Canvas>
);
}
export default App;
```
Loading 3D Models
This code demonstrates how to load and display a 3D model using @react-three/fiber. The `useGLTF` hook from `@react-three/drei` is used to load a GLTF model, which is then added to the scene using the `primitive` component.
```jsx
import React from 'react';
import { Canvas } from '@react-three/fiber';
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/path/to/model.glb');
return <primitive object={scene} />;
}
function App() {
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Model />
</Canvas>
);
}
export default App;
```
Other packages similar to @react-three/fiber
three
Three.js is a popular JavaScript library for creating 3D graphics in the browser. Unlike @react-three/fiber, which integrates with React, Three.js is a standalone library that requires imperative programming to create and manage 3D scenes.
react-three-renderer
react-three-renderer is another React renderer for Three.js, similar to @react-three/fiber. However, it is less actively maintained and has fewer features compared to @react-three/fiber, which has a more modern API and better integration with the React ecosystem.
aframe-react
aframe-react is a React binding for A-Frame, a web framework for building virtual reality experiences. While @react-three/fiber focuses on 3D graphics with Three.js, aframe-react is geared towards VR applications and provides a higher-level abstraction for creating immersive experiences.
react-three-fiber
react-three-fiber is a React renderer for threejs.
npm install three @react-three/fiber
Why?
Build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can tap into React's ecosystem.
Does it have limitations?
None. Everything that works in threejs will work here without exception.
Can it keep up with frequent updates to threejs?
Yes, because it merely expresses threejs in JSX: <mesh />
becomes new THREE.Mesh()
, and that happens dynamically. There is no hard dependency on a particular threejs version, it does not wrap or duplicate a single threejs class.
Is it slower than plain threejs?
There is no additional overhead. Components participate in the renderloop outside of React.
What does it look like?
Let's make a re-usable component that has its own state, reacts to user-input and participates in the render-loop. (live demo). |
|
Imports first
import React, { useRef, useState } from 'react'
import ReactDOM from 'react-dom'
import { Canvas, useFrame } from '@react-three/fiber'
Define a component
function Box(props) {
const mesh = useRef()
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame(() => (mesh.current.rotation.x += 0.01))
return (
<mesh
{...props}
ref={mesh}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 2, 3]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
Compose the scene
Either use Canvas
, which you can think of as a portal to threejs inside your regular dom graph. Everything within it is a native threejs element. If you want to mix Webgl and Html (react-dom) this is what you should use.
ReactDOM.render(
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
document.getElementById('root'),
)
Or use react-three-fibers own render
function, which is a little more low-level but could save you the extra cost of carrying react-dom. It renders into a dom canvas
element. Use this for Webgl-only apps.
import { render } from '@react-three/fiber'
render(<Scene />, document.querySelector('canvas'))
Show TypeScript example
import { Canvas, MeshProps, useFrame } from '@react-three/fiber'
const Box: React.FC<MeshProps> = (props) => {
const mesh = useRef<THREE.Mesh>(null!)
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame(() => (mesh.current.rotation.x += 0.01))
return (
<mesh
{...props}
ref={mesh}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 2, 3]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
ReactDOM.render(
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
document.getElementById('root'),
)
Documentation
Fundamentals
You need to be versed in both React and Threejs before rushing into this. If you are unsure about React consult the official React docs, especially the section about hooks. As for Threejs, make sure you at least glance over the following links:
- Make sure you have a basic grasp of Threejs. Keep that site open.
- When you know what a scene is, a camera, mesh, geometry, material, fork the demo above.
- Look up the JSX elements that you see (mesh, ambientLight, etc), all threejs exports are native to three-fiber.
- Try changing some values, scroll though our Api to see what the various settings and hooks do.
Some reading material:
Ecosystem
How to contribute
If you like this project, please consider helping out. All contributions are welcome as well as donations to Opencollective, or in crypto BTC: 36fuguTPxGCNnYZSRdgdh6Ea94brCAjMbH
, ETH: 0x6E3f79Ea1d0dcedeb33D3fC6c34d2B1f156F2682
.
Backers
Thank you to all our backers! 🙏
Contributors
This project exists thanks to all the people who contribute.