I'm evolving my way towards a suitable design for state with reagent given my project, and while still using distinct atoms (i'll probably switch to a single atom, but trying to explore the space of possibilities at present), I've tried to set up all state in the lexical context of the root component, as illustrated below. Idea is that this app-state
is an ordinary clojure map where the value of each key is a reagent atom.
It receives an attrs
map which is a prop (coming from data-
attrs on the html element), and its job is to initialise an app-state
map, which is not itself an r/atom
, but contains r/atom
s. The problem is, all of these r/atom
s were defined with defonce
when declared at the top of the file, which is what I've just switched from, and now the defonce
semantics is lost & figwheel hot reloading is broken.
Is there a way to preserve reloadable code while setting up state in this style?
I cannot put a defonce
inside a let
, because subsequent times that is evaluated it will evaluate to nil.
Or is there some pattern I'm missing here.
(defn a-root-component [attrs]
(let [app-state {:some-state (r/atom (:some-state attrs))}]
(fn [attrs]
[some-component app-state])))
Technically you could use memoize, but I wouldn't. By using
memoize
your introducing hidden global state, cleverly hidden where no one will think to look for it. Better todefonce
your state outside your main component and be explicit about it.Given the direction your moving I'd look carefully at things like re-frame and Keemcha which provide established patterns and tooling for working with centralized state in a sane way.