useMemo
Import
import { useMemo } from 'react'
Video Lecture
Section | Video Links | |
---|---|---|
useMemo Hook |
Description
In this section, I will show alternate ways of setting the geometry
of our mesh
using React and JSX.
By using these alternate methods, we need to consider how React will manage the objects within memory and the scene.
Before starting, replace ./src/Box.jsx
with this simplified script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
So far, we have basically used this JSX structure, but also including Props, useRef and Events.
<mesh>
<boxGeometry />
<meshBasicMaterial />
<mesh>
This is fine, and every time state changes in our Box
component, React will re-use the objects already created behind the scenes when it re-renders the scene.
We can verify that React is using the same geometry objects on each render by logging the uuid
of the geometry
of each box to the console.
We will add a useEffect
to ./src/Box.jsx
to log the geometry's uuid
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
./src/App.jsx
creates two Boxes, and each Box, has its own independent geometry and when we click the Box, we can see It's uuid
written to the console.
This is showing us that the geometry is not changing when this Box function component is re-executed by React when the state change happened during the click. This is good and recommended behavior.
Now what if we wanted to replace that boxGeometry
dynamically. One day you may want to change a mesh's geometry to a different one at runtime.
We have several ways of setting the boxGeometry
other than using the <boxGeometry />
tag.
In this example, I will declare and instantiate a new THREE.BoxGeometry()
in the function body, and attach it in the JSX.
Overwrite ./src/Box.jsx
with this code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
We are not using the <boxGeometry />
tag in the JSX anymore, but instantiating a new THREE.BoxGeometry
and appending it to the props in the mesh
tag instead.
This appears to work exactly the same. But there is a problem. This is a very small application, so in any case, the problem is likely to go unnoticed. But however, it is there.
This Box function will be re-executed every time there is a state change. This means that it will unnecessarily re-create a new THREE.BoxGeometry()
every time it's called.
Click on a Box and you will see that its geometry's uuid
is changing. This means that it is a new instance of a THREE.BoxGeometry
in memory and being rendered to the scene. Creating new objects unnecessarily is not recommended.
We can solve this problem by using the useMemo hook. useMemo
will act as cache for the geometry and return that instead of generating a new object.
Add the import for useMemo
import { useRef, useState, useEffect, useMemo } from 'react'
And modify the line
const geometry = new THREE.BoxGeometry()
to be,
const geometry = useMemo(() => new THREE.BoxGeometry(), [])
Now, when we click a Box, we can see that the uuid
is staying consistent.
This is much better.
useMemo
will cause the inner function to only run when needed. Use useMemo
when you want to keep expensive, resource intensive functions from needlessly re-running.
Now we can use this new technique, to safely replace the geometry of our Box without using any more resources than necessary.
Replace ./src/Box.jsx
with this code below, and you will see that the Box will toggle between a pre-cached THREE.SphereGeometry
and a THREE.BoxGeometry
on every click rather than re-creating new geometries each time we switch it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Note
You should only use useMemo
as a performance optimization, in case your code doesn’t work without it. First, try to find the underlying problem, and fix it. Then try using useMemo
to see if it improves performance.
Working Example
Useful Links
useMemo | reactjs.org | w3schools.com | sbedit.net |
React Logo Example | codesandbox.io |
GitHub Branch
git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout useMemo
npm install
npm start