Appearance
Hooks
FreshHooks allow you to tie or request specific information to your component. All hooks clean up after themselves once the component unmounts.
WARNING
Hooks can only be used inside the Canvas element because they rely on context!
jsx
// WRONG — this will crash
import { useThree } from '@react-three/fiber'
function App() {
const { size } = useThree() // This will crash
return (
<Canvas>
<mesh>jsx
// CORRECT — useThree inside Canvas
function Foo() {
const { size } = useThree()
...
}
function App() {
return (
<Canvas>
<Foo />useThree
This hook gives you access to the state model which contains the default renderer, the scene, your camera, and so on. It also gives you the current size of the canvas in screen and viewport coordinates.
jsx
import { useThree } from '@react-three/fiber'
function Foo() {
const state = useThree()The hook is reactive — if you resize the browser for instance, you get fresh measurements.
State Properties
| Prop | Description | Type |
|---|---|---|
gl | Renderer | THREE.WebGLRenderer |
scene | Scene | THREE.Scene |
camera | Camera | THREE.PerspectiveCamera |
raycaster | Default raycaster | THREE.Raycaster |
pointer | Updated, normalized, centric pointer coordinates | THREE.Vector2 |
mouse | Deprecated — use pointer instead | THREE.Vector2 |
clock | Running system clock | THREE.Clock |
linear | True when the colorspace is linear | boolean |
flat | True when no tonemapping is used | boolean |
legacy | Disables global color management | boolean |
frameloop | Render mode | 'always', 'demand', 'never' |
performance | System regression object | { current, min, max, debounce, regress } |
size | Canvas size in pixels | { width, height, top, left } |
viewport | Canvas viewport size in three.js units | { width, height, initialDpr, dpr, factor, distance, aspect, getCurrentViewport } |
xr | XR interface | { connect, disconnect } |
set | Set any state property | (state) => void |
get | Retrieve any state property non-reactively | () => GetState<RootState> |
invalidate | Request a new render (when frameloop === 'demand') | () => void |
advance | Advance one tick (when frameloop === 'never') | (timestamp, runGlobalEffects?) => void |
setSize | Resize the canvas | (width, height, top?, left?) => void |
setDpr | Set the pixel-ratio | (dpr) => void |
setFrameloop | Set the current render mode | (frameloop?) => void |
setEvents | Set the event layer | (events) => void |
onPointerMissed | Response for pointer clicks that missed a target | () => void |
events | Pointer-event handling | { connected, handlers, connect, disconnect } |
Selector
Select specific properties to avoid needless re-renders:
jsx
// Will only trigger re-render when the default camera is exchanged
const camera = useThree((state) => state.camera)
// Will only re-render on resize changes
const viewport = useThree((state) => state.viewport)
// You cannot expect reactivity from three.js internals!
const zoom = useThree((state) => state.camera.zoom)Reading State Outside the Component Cycle
jsx
function Foo() {
const get = useThree((state) => state.get)
...
get() // Get fresh state from anywhere you wantExchanging Defaults
jsx
function Foo() {
const set = useThree((state) => state.set)
...
useEffect(() => {
set({ camera: new THREE.OrthographicCamera(...) })
}, [])useFrame
This hook allows you to execute code on every rendered frame, like running effects, updating controls, and so on. You receive the state (same as useThree) and a clock delta (in seconds). Your callback is invoked just before a frame is rendered. When the component unmounts it is unsubscribed automatically.
jsx
import { useFrame } from '@react-three/fiber'
function Foo() {
useFrame((state, delta, xrFrame) => {
// This function runs at the native refresh rate inside of a shared render-loop
})DANGER
Be careful about what you do inside useFrame! You should never setState in there! Keep calculations slim and mind all commonly known pitfalls when dealing with loops, like re-use of variables.
Taking Over the Render Loop
Pass a numerical renderPriority value to disable automatic rendering:
jsx
function Render() {
// Takes over the render-loop, you are responsible to render
useFrame(({ gl, scene, camera }) => {
gl.render(scene, camera)
}, 1)
function RenderOnTop() {
// This will execute *after* Render's useframe
useFrame(({ gl, ... }) => {
gl.render(...)
}, 2)INFO
Callbacks are executed in order of ascending priority values (lowest first, highest last), similar to the DOM's z-order.
Negative Indices
Using negative indices will not take over the render loop, but can be useful for ordering useFrame calls:
jsx
function A() {
// This will execute first
useFrame(() => ..., -2)
function B() {
// This useFrame will execute *after* A's
useFrame(() => ..., -1)useLoader
This hook loads assets and suspends for easier fallback and error handling. It can take any three.js loader as its first argument: GLTFLoader, OBJLoader, TextureLoader, FontLoader, etc. It is based on React.Suspense.
jsx
import { Suspense } from 'react'
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
function Model() {
const result = useLoader(GLTFLoader, '/model.glb')
// The result is guaranteed to be present here — useLoader suspends the component
return <primitive object={result.scene} />
}
function App() {
return (
<Suspense fallback={<FallbackComponent /> /* or null */}>
<Model />
</Suspense>
)
}INFO
Assets loaded with useLoader are cached by default. The URLs given serve as cache keys. This allows you to re-use loaded data everywhere in the component tree.
WARNING
Be very careful with mutating or disposing of loaded assets, especially when you plan to re-use them.
Loader Extensions
Provide a callback as the third argument to configure your loader:
jsx
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
useLoader(GLTFLoader, url, (loader) => {
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco-gltf/')
loader.setDRACOLoader(dracoLoader)
})Loading Multiple Assets at Once
jsx
const [bumpMap, specMap, normalMap] = useLoader(TextureLoader, [url1, url2, url3])Loading Status
jsx
useLoader(loader, url, extensions, (xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
})Special Treatment of GLTFLoader
If a result.scene prop is found the hook will automatically create an object and material collection: { nodes, materials }.
jsx
const { nodes, materials } = useLoader(GLTFLoader, url)Pre-Loading Assets
jsx
useLoader.preload(GLTFLoader, '/model.glb' /* extensions */)useGraph
Convenience hook which creates a memoized, named object/material collection from any Object3D.
jsx
import { useLoader, useGraph } from '@react-three/fiber'
function Model(url) {
const scene = useLoader(OBJLoader, url)
const { nodes, materials } = useGraph(scene)
return <mesh geometry={nodes.robot.geometry} material={materials.metal} />
}