4 comments

[ 3.0 ms ] story [ 17.6 ms ] thread
Doesn't seem like a great fit. Immutability is a waste of memory when working with complex 3D scenes and React is already pretty processor and memory heavy.
Would help in the same way that react-dom helps the dom, especially performance. React basically manages the scene, only updating the parts that change. As for processor speed, React only mounts/unmounts, it maintains THREEs performance otherwise. In the demo for instance there are two animations, the stars are driven by the render loop (outside of react) and the thing in the middle using react-spring, which also animates outside of react.

I think the performance increase for a large project with a complex scene graph could be drastic compared to handling it manually - just like vanilla js would not easily get even with react unless you implement change detection, read/write queues, etc. With react-fibers scheduling the difference will only get larger since now it can bail out of or defer actions that would blow the 60fps frame budget.

As for memory and immutability, the actual v-dom tree is next to nothing, a node is a couple of bytes. This is the same as for a huge dom UI app with millions of divs and spans and table fields. The logical tree never hurts. One big problem with THREE has always been garbage and the object overhead - it's super easy to create leaks or create objects needlessly

    mesh.position.copy(xyz.clone())
I've been doing three for a couple of years now and to not be wasteful takes a lot of discipline as basically everything nudges you into re-creating objects since re-use can have unexpected side-effects. With the reconciler you can stow away objects into the graph, which means they're managed. Probably will reduce the memory footprint in the end, even with a v-dom on top.
Cool! But why and when? How would I use loaders with this? (GLTF etc)
You would use them as you always did. You have raw access to everything. But if you want loading results to be managed, put them into useEffect/useMemo and render out the results. For instance i've just made a text-sprite component that looks like this:

    function Text({ children, ...props }) {
      const { camera, size, viewport } = useThree()
      const { width } = viewport()
      const canvas = useMemo(() => {
        const canvas = document.createElement('canvas')
        canvas.width = canvas.height = size.width * 2
        const context = canvas.getContext('2d')
        context.font = `bold ${size.width *
          0.45}px -apple-system, BlinkMacSystemFont, avenir next, avenir, helvetica neue, helvetica, ubuntu, roboto, noto, segoe ui, arial, sans-serif`
        context.textAlign = 'center'
        context.fillStyle = 'black'
        context.fillText(children, size.width, size.height + size.width * 0.4)
        return canvas
      }, [children, size.width])
      return (
        <sprite scale={[width, width]} {...props}>
          <spriteMaterial name="material">
            <canvasTexture name="map" image={canvas} premultiplyAlpha onUpdate={s => (s.needsUpdate = true)} />
          </spriteMaterial>
        </sprite>
      )
    }