bhauman / devcards

Devcards aims to provide a visual REPL experience for ClojureScript
1.53k stars 116 forks source link

Should defcard-rg pass initial-data as an RAtom rather than an Atom? #111

Closed eyelidlessness closed 7 years ago

eyelidlessness commented 7 years ago

Repro (minimal)

(defcard-rg some-thing
  (fn [state _]
    [:div (pr-str (type state))])
  {})

Expected

This will render reagent.ratom/RAtom.

Observed

It renders cljs.core/Atom.

More detail

Since Reagent uses reagent.ratom/RAtom to trigger re-render, a devcard with certain functionality may not re-render as expected.

I experienced this problem with a Reagent component with a button that that called (swap! state ...) on click. I had :inspect-data true on the card, the inspected state re-rendered, but the Reagent component in the card never did.

Workaround

I really don't like this, but it's what I did to move forward on my project. Others might find it useful if they encounter the same problem:

(defn as-ratom
  "Devcards provides a cljs.core/Atom, we need a reagent.ratom/RAtom. This:

  1. Creates an RAtom
  2. Watches the state of the provided Atom, updating the state of the RAtom
  3. Vice versa of step 2
  4. Returns the RAtom"
  [atom*]
  (let [ratom (reagent/atom @atom*)]
    (add-watch atom* ::mirror-state
      (fn [_ _ prev x]
        (when-not (= prev x)
          (reset! ratom x))))
    (add-watch ratom ::mirror-state
      (fn [_ _ prev x]
        (when-not (= prev x)
          (reset! atom* x))))
    ratom))
piotr-yuxuan commented 7 years ago

Hey, I'm having the same issue, thanks for your feedback ^^ Where do you put this function?

eyelidlessness commented 7 years ago

I realized you can just pass an RAtom as the initial data, rather than a plain map. That's plenty good enough for me.

piotr-yuxuan commented 7 years ago

Actually, what about you don't want a full RAtom (such as app-db in reagent + re-frame) but much more a reaction on it (just to get a part of it)?