Figwheel reloadable code with atom as local (lexical) state?

81 views Asked by At

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/atoms. The problem is, all of these r/atoms 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])))
1

There are 1 answers

0
Walton Hoops On

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 to defonce 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.