This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-27
Channels
- # bangalore-clj (1)
- # beginners (27)
- # boot (16)
- # cider (14)
- # cljs-dev (94)
- # cljsrn (8)
- # clojure (229)
- # clojure-dev (5)
- # clojure-dusseldorf (6)
- # clojure-italy (8)
- # clojure-norway (8)
- # clojure-russia (22)
- # clojure-sanfrancisco (2)
- # clojure-spec (48)
- # clojure-uk (44)
- # clojurescript (47)
- # core-async (87)
- # cursive (43)
- # datascript (22)
- # datomic (20)
- # defnpodcast (5)
- # emacs (6)
- # hoplon (4)
- # jobs-rus (4)
- # keechma (2)
- # klipse (8)
- # leiningen (2)
- # luminus (2)
- # lumo (14)
- # om (38)
- # onyx (4)
- # overtone (3)
- # pedestal (41)
- # planck (72)
- # powderkeg (42)
- # proton (46)
- # protorepl (9)
- # reagent (9)
- # ring (47)
- # ring-swagger (5)
- # rum (7)
- # sql (22)
- # unrepl (1)
- # untangled (24)
- # vim (19)
- # yada (5)
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.
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.
Still, since I have components that are quite expensive to render, I'm going to use this for now.
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)))}))
This lets me pass a function that will initialize the atom based on component args. It sometimes leads to code duplication, but works well.
@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