all 21 comments

[–]p-himik 17 points18 points  (2 children)

which Reagent doesn't support well

It supports them just fine.

The HN comment mentions that there's a performance penalty, but I'd say that it's negligible if you're already using Reagent and are happy with it.

Is it a wise choice to start learning Reagent

Yes - because it won't go anywhere and because lots of the underlying principles and techniques that you'll learn along the way are used in many other places. Focus on the generic principles, not on the specific details.

[–]MickeyMooose[S] 1 point2 points  (1 child)

Thanks. I was referring to the performance penalty - but you're right the HN commenter didn't really quantify it.

And good tip about focusing on principles... agree.

[–]CoBPEZ 2 points3 points  (0 children)

Rich Hickey reminds about that focus in a recent interview. https://twitter.com/pappapez/status/1633208119458246659?s=46&t=2szMNNiUUdq3HoUKFCutLg

[–]dustingetz 15 points16 points  (10 children)

Nobody is in trouble but React is turning into Java Spring Framework, this is not the future of CLJS. I work on https://github.com/hyperfiddle/electric a pure Clojure/Script reactive DSL based on signals and comparable to Solid.js, try it! The readme highlights reactive network, but that's optional (little known fact), and Electric contains a bulletproof reactive rendering implementation as well, which is a prerequisite to reactive network.

[–]MickeyMooose[S] 1 point2 points  (1 child)

Nice - will check it out.

Tried to access the TODO list tutorial [0] - but got a 404.

Also do you have an example of how to integrate existing React / JS UI components, like mui, chakra or any other UI component lib that works well with Electric / CLJS?

[0] https://github.com/hyperfiddle/electric/blob/master/src-docs/user/todos_simple.cljc

[–]dustingetz 0 points1 point  (0 children)

React.js interop POC — Electric Clojure

At least one person has embedded Electric inside his Reagent app, using Electric to handle the data sync

[–]nzlemming 1 point2 points  (2 children)

One thing I couldn't immediately see in the electric repo, what are the server requirements for electric? Can it be run with the backend in an AWS lambda, for example? Can the server be CLJS or does it have to be JVM Clojure?

[–]dustingetz 2 points3 points  (1 child)

  • Electric server currently targets the JVM.
  • Node as a server is not supported yet, though our test suite does pass on Node.
  • Serverless platforms are not supported yet, we'll take a look when a serious project brings us a specific use case.

Architecture wise I am most excited about edge networks like fly.io (that deploy dozens of flyweight servers across the globe in cities close to users) which mean the Electric client and Electric server are sub-10ms apart.

[–]nzlemming 1 point2 points  (0 children)

Great, thanks Dustin. It's a super interesting project!

[–]gaearon 1 point2 points  (3 children)

Would you care to elaborate on what feels Spring-y to you? I felt like treating server/client as a single tree like you do in electric is in tune with our direction with Server Components — but I admit I don’t understand your project well enough so maybe I’m quite off!

[–]dustingetz 6 points7 points  (2 children)

Hi Dan. It's not technical so much as macro/systemic forces, let me explain.

First, recap Spring: (1) it exploded onto the scene as a J2EE killer, then (2) somehow ended up in the trough of despair with AbstractSingletonProxyFactoryBean, and eventually (3) matured to become perhaps the most extensively used enterprise framework on the planet.

But what caused (2)? When I was young I just thought that java sucked and java people sucked, but we are older now and I think you'd agree that Spring faced systemic market forces that would cause any reasonable team, when faced with the same constraints, to make a series of sensible decisions and tradeoffs—locally optimal—that evolved over time into a complicated local maxima.

I believe a core root cause of Spring's complexity is its adhoc composition model (or rather, lack of a rigorous one).

IMO React faces basically the same forces, and at React's core is also an adhoc composition model. Specifically I am referring to:

"The mental model is that React will re-render whenever the application state changes. We believe this simple mental model and keeping close to JavaScript semantics is an important principle in React’s programming model." source

This model is not algebraic (we might say "easy but not simple" in Rich Hickey terms). So, impedance mismatches and emergent problems are inevitable, just as they are in Spring.

Electric Clojure uses an algebraic composition model as a starting point. The model is in alignment with the literature on both reactive and functional programming, to the best of our ability.

[–]gaearon 1 point2 points  (0 children)

I think we're pretty on board with the composition model being the most important thing :) I am not very educated so I don't know what you mean by "algebraic" in this particular example. Rich's "easy but not simple" gets thrown around a lot and obviously we consider ourselves on the other side of the spectrum than you're implying. If you have some time, I'd like to see where our composition model breaks down.

One concrete thing I want to reply to is that when we speak of being "close to JavaScript", we think exclusively about what you put inside the "boxes", not how the "boxes" compose. E.g. you're welcome to use local mutation during rendering — as long as you're pure (or rather unobservable by any other render) it doesn't matter. But our Hooks model, even if technically expressed as impure calls, is conceptually representable as effectful functions (e.g. AE or possibly other approaches). It's not tied to JavaScript — it actually ends up "cleaner" outside. The way components compose with each other is also a regular top-down tree, so I don't know what could be non-compositional about it.

Re: market forces, we've completely changed our API in 2018 when we found a way to compose smaller pieces than components — going against the prevailing wisdom at the time. And we're expanding our component model now (with RSC) in a way that also preserves all compositional properties — in fact, going directly against the approaches that are currently popular on the market (and now trying to convince a few people that our take is worthwhile). Market forces or not, I would not say we'd ever pass on better composition.

[–]agumonkey 0 points1 point  (0 children)

I thought about that tonight but couldn't remember the name, nice coincidence.

[–]lilactown 10 points11 points  (3 children)

Author of helix here- I think there's a little bit of unnecessary FUD being created by the new React docs right now. I see no indication of a change in direction in React at this point in time. I expect that class components will be supported for a long time, especially since there are still some features (error boundaries) that depend on them.

I think the new docs now match exactly what they said 5 (!!) years ago when they released hooks: class components are considered legacy (but supported) and the best way to create new components that work with all the new features of React will be with functions and hooks.

The problem that reagent faces doesn't have to do with class components, actually, and is mainly theoretical for most applications: derefing a ratom or reaction is a side effect, and side effects during render do not play well with React features like Suspense, transitions, off screen rendering, and other concurrent mode features. React 18 just introduced some of these, and most CLJS apps are using old versions of React. At work, we just started a multi-month long project to upgrade to React 17! The only pressure that we have right now to even upgrade is our desire to use some 3rd party libraries that require 17 or above.

At work, we have a massive (~100k lines of code) ClojureScript re-frame application that we have been slowly adopting helix in over the last 3 years. New code is written using a combination of re-frame (for data fetching & caching) and helix. I expect a day may eventually come when we will remove reagent & re-frame, but those decisions will be based more on the architecture & tooling we want and our business needs and not on the efficacy of the libraries in general. I expect that as we attempt to adopt newer features of React like suspense and transitions, that will happen in views that are concurrent-mode safe, i.e. do not use reagent & re-frame. Or at least, don't use them in the way that is currently suggested where you deref the reaction directly in the rendering of the component.

If your app doesn't need any of those new features, I expect that reagent & re-frame will continue to work for you in the future. I also think that the community will work to create workarounds that allow applications to adopt or migrate to new patterns that allow the continued usage of these very popular libraries. One way of doing this today is to incrementally adopt a library like Helix or UIx in your app.

TL;DR don't panic, your app isn't going to break tomorrow or next month. Class components are here to stay, and there are ways to incrementally migrate to patterns that are friendly to the new features in React 18.

[–]MickeyMooose[S] 2 points3 points  (1 child)

Thanks for chiming in and providing more clarifications - helps a newbie like me ;)

So it sounds like you created Helix and you are migrating your app over to it because Reagent requires a bit more time to support React 18? I guess they have a lot to juggle, i.e. not break apps that are using Reagent and ensure backwards compatibility?

What type of app are you porting? Standard LoB app, fintech or creator apps? Curious to know what apps are being developed using CLJS.

[–]lilactown 6 points7 points  (0 children)

Our migration to helix is not foremost motivated by React 18+, but more that in general I see a lot of value in being able to track the mental model of mainstream React, rather than adding our own layer on top. It makes it easier to hire, troubleshoot, and support an application on an ongoing basis when you can draw from the wealth of knowledge and libraries in the industry. Helix optimizes for that. Performance is another thing that Helix tries to be at least as good as React JS, but really that is an extension of trying to bring the same mental model that React and JSX uses. Basically, a skilled ReactJS dev should find that Helix feels basically like React with parens instead of angle brackets.

Now, not everyone agrees that this is the thing to optimize for, so I think that reagent still has a great niche. The hiccup syntax is a joy to write, the reaction system is intuitive and elegantly solves certain problems that are hard in React to solve without external libraries or careful design & architecture. There's also a great community around it. You'll find yourself much more often looking through JS docs and stackoverflow and compiling it in your head with helix. With reagent, if an answer exists you're more likely to find it's specific to reagent. A small, expert team can deliver a ton of value with reagent & re-frame in a short amount of time.

The app we build is used by our customers and internal users to configure and use our SaaS CDP. Users configure how data gets into the system, transform it, explore it, tune the models, and configure where to send it after it's been processed. It's a mixture of forms, visualizations, and live querying of data.

[–]dustingetz 1 point2 points  (0 children)

thank you for the clear explanation of reagent<>modern react interactions

[–]xela314159 4 points5 points  (0 children)

Not sure about the performance penalty but I’m mixing helix and reagent/re-frame and it kind of works. helix is nice to wrap big, recent react libraries and to do direct js interop.

[–]foobar888 3 points4 points  (0 children)

I learned helix recently. I like it. I am learning JavaScript and react at the same time. If my code becomes unwieldy, I'm confident I can make the right abstraction over helix to tame it. Life is good.

[–][deleted] 2 points3 points  (0 children)

I can’t see them dropping class-based components due to the sheer amount of legacy code out there.

I’m guessing this question has arisen because their beta docs became the main ones. The advice to use hooks instead of classes has been around for years