"Reagent is the recommended approach for building ClojureScript applications with Luminus."
Reagent is nice, but if you want global state management, re-frame adds most familiar concepts from redux but without as much boilerplate: https://github.com/day8/re-frame
Indeed, you wouldn't (probably) use re-frame unless you're also using reagent (although you could).
I think vga805 is referring to the "atom pattern" where you have a atom on the outside and/or inside the components that you interact directly with, which is mostly (but not always) replaced by subscriptions and setting up dispatches.
So re-frame would replace the typical state management pattern you use when you're using reagent, but it wouldn't replace the view layer.
re-frame still adds way too much boilerplate for my tastes, especially on solo projects. I personally greatly prefer to use reagent directly over using re-frame.
Yes. I now use Rum + Datascript + core.async for event sourcing. Here is the entirety of my reactive event-loop handling, inspired by Tonsky's Cat Chat (https://tonsky.me/blog/datascript-chat/):
; One Macro in events.clj:
(defmacro go-loop-sub [pub key binding & body]
(let [[db-bind & bindings] binding]
`(let [ch# (cljs.core.async/chan)]
(cljs.core.async/sub ~pub ~key ch#)
(go-loop []
(let [event# (rest (cljs.core.async/<! ch#))
~db-bind @yourproject.data.core/conn
~(vec bindings) event#
result# (do ~@body)]
(when result#
(yourproject.data.core/transact! yourproject.data.core/conn result#)))))
(recur)))))
;; Usage (at top of core file)
(defonce conn (d/create-conn schema))
(defonce event-bus (async/chan))
(defonce event-pub (async/pub event-bus first))
;; For each event you want to dispatch on:
(go-loop-sub event-pub :todo/add-item [db {:as data :keys [text]}]
;; Query db here. Any tx-data you return will get transacted.
[{:db/id -1
:todo/text text}])
;; To display some reactive queries in DataScript:
(rum/defc root-component
< rum/reactive [conn]
(let [db (rum/react conn)
todos (d/q '[:find ?todo ?text
:where [?todo :todo/text ?text]]
db)]
[:div "Todos: " (pr-str todos)]))
I use those same 3 in a similar way, it's great. I do really appreciate the design of the effects/coeffects concept in re-frame, I often use that concept. I just don't find I ever need re-frame.
We've had a great experience building a mid-size app with re-frame. Sure, writing subscription and event handlers and wiring it all together seems like a lot of boilerplate when you could just fetch().then(), but in the long run the architecture really pays off.
It's not perfect, I do lament the boilerplateyness myself, but I have not seen anything better in my decade of web dev.
I think one thing re-frame does well is cascading events. One event might trigger other events, etc. There is also a library for orchestrating re-frame events: https://github.com/day8/re-frame-async-flow-fx
I think using re-frame rather than just building event loops yourself with channels and atoms give you some advantage in terms of existing libraries and utilities.
For solo projects that don’t need all the boilerplate I think Hoplon is an even better option (there’s a Luminus profile for it). It’s kinda like Svelte: it doesn’t use a vdom and makes interacting with the actual dom really simple: http://hoplon.io/
Hm, really? Maybe you're missing a layer of indirection if that's so?
Usually I end up wrapping things myself so I have one "setup-handler :name" function/macro that creates the subscription and event db handler for me. There are also existing libraries that does this for you, if writing it yourself is not wanted.
Reagent is good for starting if you are new to React, but quickly becomes limiting.
I found Rum (https://github.com/tonsky/rum) to be a much more flexible choice. It doesn't force you into a single way of doing things, but rather offers a composable way of adding behavior to components using mixins. Especially for larger and more complex applications this proves to be a good tool.
Another thing which I really like about Rum is "isomorphic rendering" (not a good name, but I didn't invent it) — pre-rendering the DOM on the server instead of shipping an empty page to the client and requiring the client to render everything using JavaScript.
Reagent and rum both wrap react right? Do they mirror the react hook logic in some way? E.g rum/react might be a ones to one with reacts use state hook.
Do you mean cursors everywhere, or actual atoms? I maintained a fairly large project (3 man years or so) that used local atoms only for ephemeral components where you'd want to lose their state when hidden.
Components were passed cursors in to a single global atom, which more or less worked OK.
I think I'd use the re-frame model starting from scratch, but managing the app's state was probably not a top 5 problem for me. Every program is different of course!
Integrating external libraries, validating data, server side rendering, caching remote queries and tracking down compilation/logic errors would probably be my top 5. This was 5 years ago though.
Reagent is nice, but if you want global state management, re-frame adds most familiar concepts from redux but without as much boilerplate: https://github.com/day8/re-frame