useRef that inits once

I don’t work with the react three wrapper, but i do work with react and threejs together often. I sometimes need to do something like useRef(new Camera() but this actually creates a new camera each time the react component renders.

Not directly related to three, but FWIW, i made myself a different version of useRef that allows what useState does, which is useRef(()=>new Camera()). This way the camera is only created once.

It’s available here.

Is that part of the react debug mode double init lifecycle bs?

Nah, more like, you really really need useRef with something like three, because its basically a wrapper around some value, like a uniform, {value:new Vector3} this is just {current:new Vector3} . However, by design it just calls it and calls it, even though it uses the first instance.

The other hook that is even more fundamental allows you to pass this function. Sure you may be recreating the function often, but at least youre not calling something like Orbitcontrols that attaches listeners and such.

1 Like

Well why don’t we simple use the pre-made hooks given by React-Three-Fiber. Such as useThree and useMemo. I mean useMemo was made due to the reason that when you instantiate an object using the THREE component it changes the UUID of the object every time React scene renders. In other words it simply creates new geometries each time.

I think you did a great job creating something that is crucial and can play an important role but why spend time on something which is already there. :smile:

const foo = useMemo(() => new Camera(), [])
const [bar] = useState(() => new Camera())

As for orbit controls, no way to create it only once in react due to a known bug in three, the class has constructor side effects so it cannot be dynamically created and closed without leaving traces (handlers). React runs components twice in strict mode to flush out defects. Fiber solved this through three-stdlib. GitHub - pmndrs/three-stdlib: 📚 Stand-alone library of threejs examples designed to run without transpilation in node & browser

Exactly thats what I am trying to say!

Well, this is specifically meant for use without react-three-fiber. I wouldn’t want to pull in that whole dependency just for this two line hook. Is that what you are asking or why im not using react-three-fiber to begin with?

Well, the useMemo in particular because of this:

useMemo is allowed to flush, but useState is stable. But unfortunately both don’t solve the orbit controls issue, this is something that only threejs can fix, or you fork it like stdlib did.

I shouldn’t have mentioned orbit controls, i meant mostly things like new Vector3 i just didn’t want the constructor to be called all the time, regardless of any side effects inside.

But interesting points were brought up here.

Going to this useMemo that was linked, the example definitely uses them:

const geom = useMemo(() => new BoxGeometry(), [])
const mat = useMemo(() => new MeshBasicMaterial(), [])
return items.map(i => <mesh geometry={geom} material={mat} ...

I only found out about the comment above recently, so i guess they never made that change, but this example is basically risky? Either useState or useRef would guarantee that it’s stable, useMemo does not. At least according to Dan Abramov, an authority on React, it seems that it’s an anti pattern.

Is it fair to assume that there are a lot of three fiber apps our there that heavily leverage useMemo for these “I need to instantiate something once when the component mounts”? If so, is what Dan Abramov mentioned ever going to be a problem?

The other interesting point is:

@AshhadDevLab I hope this answers a bit of your question. Orbit controls were already there, but someone needed a slightly different version, so they forked it. This is very common in open source i think.

I whipped this up in a few hours, kind of a blend between orbit controls and trackball controls. Those are all just examples anyway.

So to reiterate useMemo is not from three-fiber AND it doesn’t do this (or what i need).
useThree may be from react-fiber but im not using it, three is instantiated somewhere outside of react and all that.

1 Like

You’re talking about the fact that all those classes take a dom element and attach listeners to them?

I’m trying to get feedback on reddit and i think the approach is sound. I also think that people outside of graphics generally seldom use useRef outside of targeting dom elements.

I whipped up this sandbox to demonstrate the approach. Imagine if it’s new SphereGeometry() iw ould be creating and discarding all those arrays all the time.

https://codesandbox.io/p/sandbox/useref-yydrkz?file=%2Fsrc%2Findex.tsx