Fork me on GitHub
#rum
<
2017-03-27
>
jrychter07:03:26

Well — I did change it to :init and it works just fine, so perhaps that should be done (it would allow me to use local state in my other :init functions. But that doesn't solve my problem, which is: how to initialize the atom using component args without triggering additional re-rendering.

jrychter07:03:28

As it is now, if I reset! the atom in :init, the watch gets called and I get two initial renders instead of one. The only way around it that I found was to place an additional condition in the watch fn: (when-not (= old-state initial) …), which avoids doing the initial render. But that's a bit of a hack, because you then have to use a "special" initial state that can never occur later.

jrychter07:03:42

Still, since I have components that are quite expensive to render, I'm going to use this for now.

jrychter08:03:14

Another solution I came up with is this:

(defn arg-local
  "Mixin constructor. Adds an atom to component’s state that can be used to keep stuff during component’s
  lifecycle. Component will be re-rendered if atom’s value changes.  Atom is stored under user-provided key or under
  `:rum/local` by default. If a function is passed as the initial value, the function will be called with component's
  args and the return value will be used to initialize the atom."
  ([initial] (arg-local initial :rum/local))
  ([initial key]
   {:init
    (fn [{:keys [args :rum/args] :as state}]
      (let [local-state (atom (if (fn? initial)
                                (apply initial args)
                                initial))
            component (:rum/react-component state)]
        (add-watch local-state key
                   (fn [_ _ _ _]
                     (rum/request-render component)))
        (assoc state key local-state)))}))

jrychter08:03:26

This lets me pass a function that will initialize the atom based on component args. It sometimes leads to code duplication, but works well.

tonsky08:03:05

yeah, I’ve used kind of similar technique once

jeroenvandijk10:03:22

@jrychter I’m currently experimenting with a variation of rum/local, a mixin that only gives an atom under a key, but doesn’t do anything with rendering. Sub-components are reacting on changes on this atom via rum/react. I guess this could be an approach for you as well, not sure what is cleaner