Hacker News new | past | comments | ask | show | jobs | submit login
Headless React (acko.net)
201 points by jashkenas on July 6, 2021 | hide | past | favorite | 24 comments



This is part 3 of a 3 part series. If you’re confused, start at #1, but even then it moves very quickly through a mountain of content, with some assumed familiarity with some aspects of graphics programming in #3. Detailed knowledge about how React fiber works is a mandatory prerequisite and it would help if the posts told you what you were expected to know first.

Most importantly there is working code if you actually click on the links. I didn’t at first and missed it because it’s not obvious which are crucial to click on. Here it is: https://gitlab.com/unconed/use.gpu

Post #2 about “data flow graphs (DFGs)” and post #3’s brief treatment of the double-tree sowing and reaping thing might be easier to understand if you have watched this talk about Jane Street’s Incremental, specifically how the various iterations address the dynamic complexity introduced by the `bind` function:

https://www.youtube.com/watch?v=G6a5G5i4gQU

The whiteboard drawings there are fantastic. Yaron starts very near zero and builds steadily from there. Acko’s posts start at 900 in about five different domains and zoom to 4900 in each. Of course at 4900 you have a pretty cool and way out of my league declarative and reactive GPU render pipeline but maybe slow down for us a bit!


Hot (uninformed) take:

The effect system described in the first post immediately reminded me of re-frame, a Clojurescript library that uses React under the hood. I don’t know how similar this flow is to that, but they share the key axiom that “declaring an effect should be orthogonal to running it.”

I kind of hate generators, so I’m deferring the rest of the article/series until I’m not heat-angry and can read it more in the spirit of curiosity =)


The term I use to describe this phenomenon is treating side-effects as data. https://erock.io/2019/04/12/simplify-testing-async-io-javasc...


The example function in the article `fetchAndSaveMovie` is (deliberately, I know) not well-written. If it were composed of 2 functions `fetchMovie` and `saveMovie`, each of which does one thing, then each could be tested separately. If the composed function then needed to be tested, it would only need to test that each function were called in succession, but personally I wouldn't think it necessary.

With that small change, I'm not sure how essential is the rest of the approach. I'm definitely not saying that the approach isn't possibly valuable, more that I don't think the article argues for it very well. It introduces complexity to cover for poorly-written code. I think if it were to start out with excellent code and demonstrate an unambiguous improvement, it would be a better argument. My 2c


From a quick skim and from a few Google searches I cannot find a definition of "headless React". The first sentence in this post already assumes you know what it means, as do most other sites I can find that mention it. Can anyone enlighten me?


A headless component is one that does not return anything for a render by default. It either accepts a prop function the does the render or passes values to its children and lets them render the results. This splits the functionality from the render so the developer render as appropriate in the application's context is (ie. web page, react native, etc). The headless component may come with multiple styles of renderer available.


But an headless React is only tangentially related to headless components.

Acko is building a React alternative that follows all React semantics but without any render at all. That means no DOM, no nothing. Just components and effects (un)mounting and updating.


Isn't this what Solid.js does, aside from semantics strictly equal to react?


> without any render at all. That means no DOM, no nothing. Just components and effects (un)mounting and updating.

Don’t we call that the VDOM?


The virtual dom concept and this blog’s concept has this in common, but this is different because this blog is generalizing it away from the dom. For an example, it applies ideas to graphics (via WebGPU).


It has nothing to do with components. It’s about using react to render to anything, not just a virtual DOM.


Acko is back (not that they went anywhere, just excited to see it on HN)! This is one of my favorite personal tech blogs of all time, so many cool easter eggs and animation gems hidden in there. I especially love the Winamp visualizer projects and inspirations you can find sprinkled throughout.


[flagged]



> The main thing something like React provides is a universal power tool for turning things off and on again: expansion, memoization and reconciliation of effects.

This should be React's tagline.

Once you see React this way, it becomes a tool to design an application architecture rather than just a UI library. The hierarchical nature of React makes it easy to picture the ownership and lifetime of a state.

I'm wondering if Headless React can be used, for example, as a side-loaded app to control systems in ECS in plug-and-play manner.


Is the performance gain huge if you remove the virtual DOM completely?


It seems like a mis-match to me to try to use React for 3D. Like if all you have is a hammer than everything is a nail. 3D is not a tree, only the scene graph is, geometry and materials are not leaf nodes.

Think about HTML and Images. Image tags `<img>` live inside the DOM tree but the image itself, the actual pixels, are referenced only by name and those resources are managed outside of React. From React's POV doesn't know about the actual images. It only knows about these HTML tags called `<img>` that are references to the actual image. Two or more img tags can reference the same image by using the same src and something outside of react loads, frees, and otherwise deals with them.

In 3D you have the same problem a geometry, or mesh-data, like a cube or human, might be referenced 2 or more times. If you want to cover a globe with cubes you might have 1000 cubes. But, like an image, all you want is references to a single cube and that single cube, following React's example with HTML, would live outside of React. It can't be part of the DOM hierarchy because it doesn't fit the definition of "hierarchy". Its references do but its data does not.

The same with materials. In React, if you want 2 elements to share a style you use className="nameOfStyle" and the actual style lives outside of React in CSS. You have the same issue with materials in 3D. You might want 247 of your 1k cubes above all to share the same material as they represent the same area so that you can highlight them collectively, but now you're creating something that doesn't live in a tree, just like in className="nameOfStyle", nameOfStyle doesn't live in the tree.

I'm not saying they're aren't solution, just that off the top of my head, declaring <Scene><Cube/><Cube/><Cube/></Scene> is wrong. It should be <Scene><Renderable geo="cube"><Renderable geo="cube"><Renderable geo="cube"></Scene> and now you're left figuring out how to declare what the string "cube" represents but it will look nothing like React JSX. I get that react-three-fiber does the former but it's arguably wrong as it's pretending something is a hierarchy that's not a hierarchy. See the image example above.


I've worked with react-three-fiber a little bit so maybe I can offer some experience. RTF is not awesome because React is the best, or even a particularly good way to describe 3D objects. It's awesome because if you are already building a React app you can integrate 3D objects into your app and build user interactions using the same model as the rest of your application. The idea is to be able to bring in 3D models and add things like onHover events and animations as if they are DOM nodes like the rest of your application is. It has worked really well for me, there is a tool that turns Blender models into JSX so you never have to worry about that.


What tool is that?



the scene is a real graph. the difference between imperative and declarative becomes more evident with examples, for instance three: https://codesandbox.io/s/basic-threejs-example-with-re-use-d... and react: https://codesandbox.io/s/basic-react-example-with-re-use-e2z...

declaring the graph in combination with hooks is how you form self-reliant components.

as for leaf nodes, if they pre-exist they are declared as props, but you can also declare them. they are part of the graph. the only difference is that they don't go into "children".


> So for now I have to write my code in the promise.then(…) style instead of using a proper yield.

Well - using ".then()" is the proper way of doing things. Just add do-notation and you are good.

Maybe eventually the javascript community will catch up :^)


I would not suggest using yeet for the word, as it is actually a meme word


Should enough people use it, it'll be yeeted into the dictionary and cease being a meme word. Language is like a living thing, it grows and changes.

Honestly, I'm on board with 'yeet'. It's versatile, playful, and is unambiguous as to what it means (transferring something quickly from one place to another).


It's a perfectly cromulent word.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: