Asking for advice on manage three.js with React and data-driven rendering possibility in react-three-fiber
See original GitHub issueHi, thanks for sharing react-three-fiber with developers! I got really a lot thoughts in how to manage three.js application with React from this project.
Currently, I’m going to make a series of data visualization tutorials from scratch, and I also created a repository in GitHub call glmaps. In a word, glmaps is a project full of bunch of earth and map visualization examples based on three.js and deck.gl, as well as some tutorials for visualization beginners, in which I realized a small three.js application manager, too.
The manager I created is quite simple, but can cover the basic needs, such as Curve Animation, I may ask you for advice in better coding, that is how will you organize the codes if you need to realize it.
1. The background and question description
I created a globe with three.js, in which I have a visualization type named “Curve Animation”(Something like arc animation from origin to destination). I handle this requirement with dividing it into two parts currently.
- Manage three.js scene with React (with Hooks, Hooks is really good!)
- Animate Curve with
setRangeand force it update
1.1 Manage three.js
My idea is quite simple, I provide a three.js wrapper for react developers (I know it lacks a lot of reactive things):
const ThreeCube = (props) => {
useEffect(() => {
if (!data.length) return () => {};
const [cleanFunc] = threeEntryPoint({
...props
});
return () => {
cleanFunc();
};
});
return (
<canvas
id={id}
/>
);
};
in which developers can handle his three.js application just like write plain JavaScript. In which threeEntryPoint is entry point for SceneManager, and the later is a function which can handle the whole three.js application lifecycle.
const threeEntryPoint = ({id, ...otherProps}) => {
const canvas = document.getElementById(id);
const sceneManager = SceneManager.getInstance(canvas, otherProps);
raf = null;
function bindEventListeners() {
window.addEventListener ("resize", resizeCanvas);
resizeCanvas();
}
resizeCanvas = function() {
// ...
}
const render = () => {
// ...
}
bindEventListeners();
render();
const cleanFunc = () => {
const gl = canvas.getContext('webgl');
gl.clearColor(1.0, 1.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
window.removeEventListener("resize", resizeCanvas);
cancelAnimationFrame(raf);
SceneManager.destroyInstance();
}
return [cleanFunc];
}
1.2 Animate Curve
Definition of Curve (the orange lines in the picture): Curve is actually THREE.Line made with THREE.BufferGeometry (so I can control which part of this line be rendered to the scene, with the help of setRange method)

The structure of my scene is:
- Put multiple
Curve(which isTHREE.Line) inTHREE.Meshcode - Put the
THREE.BufferGeometryused inCurvein an array (suppose it’s named curveMesh) code - Put
THREE.MeshinTHREE.Group, and putTHREE.GroupinTHREE.Scenecode
and then when I need to update the Curve, I get the array and manipulate it like this:
curveMesh.children.forEach((path) => {
path.geometry.setDrawRange(index, 20);
path.geometry.attributes.position.needsUpdate = true;
})
and then back to the title of this issue (sorry for that, but I think only in this way I can express my thoughts completely…).
2. How to make data-driven render possible with react-three-fiber
I wonder how can I do it with react-three-fiber if I want to realize the above animation? According to README, I think I may code it in this way possibly:
import { Canvas } from 'react-three-fiber'
function App(props) {
const {curvesData = []} = props;
return (
<Canvas>
<group>
<mesh
geometry={new THREE.BoxGeometry(1, 1, 1)}
material={new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true })}
>
{curvesData.map((curve) => {
<line
geometry={new THREE.BufferGeometry()}
// MY THOUGHTS
onUpdate={(instance) => instance.setDrawRange(SOMETHING, SOMETHING, etc)}
/>
})}
</mesh>
</group>
</Canvas>
)
}
but how can I insert setDrawRange method, I’m not sure whether it’s right to put it inside a onUpdate callback?
And another question is that what’s your consideration in designing the API of react-three-fiber? Since I find you may want developers provide objects like geometry manually, rather than a data-driven API like D3?
The way D3 handle it:
d3.select("body")
.selectAll("p")
.data([4, 8, 15, 16, 23, 42])
.enter().append("p")
.text(function(d) { return "I’m number " + d + "!"; });
I supposed react-three-fiber may do it like this (if it’s good to do it in this way):
import { Canvas } from 'react-three-fiber'
function App() {
return (
<Canvas>
<group>
<mesh
geometry={new THREE.BoxGeometry(1, 1, 1)}
material={new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true })}
data={data}
customRender={(item, index, instance) => {
// instance: the object itself
// item: current data item, equals to data[index]
// index: current data item index
// customized logic here
}}
/>
</group>
</Canvas>
)
}
Thanks for your sharing, again! react-three-fiber is really awesome!
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (3 by maintainers)

Top Related StackOverflow Question
1
The first is possible:
You don’t need the resize event, it auto adjusts with a resize observer, meaning that it can even respond to changes if it isn’t fullscreen.
2
You still have full access. I realize that in some situations pure declarative support is probably not possible since three has so many access functions. A good way could be to break these up into small, contained components instead.
Thanks for sharing your thoughts!