This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-06-10
Channels
- # aleph (4)
- # announcements (27)
- # aws (12)
- # aws-lambda (1)
- # beginners (207)
- # boot (4)
- # calva (8)
- # cider (9)
- # clj-kondo (9)
- # cljs-dev (27)
- # cljsrn (6)
- # clojure (104)
- # clojure-android (3)
- # clojure-dev (9)
- # clojure-finland (2)
- # clojure-italy (18)
- # clojure-spec (8)
- # clojure-uk (100)
- # clojurescript (43)
- # clojutre (1)
- # core-async (49)
- # cursive (18)
- # data-science (3)
- # duct (24)
- # events (2)
- # fulcro (27)
- # immutant (1)
- # off-topic (32)
- # om (2)
- # onyx (2)
- # pathom (14)
- # pedestal (2)
- # planck (3)
- # re-frame (38)
- # reagent (7)
- # reitit (10)
- # rewrite-clj (7)
- # ring-swagger (3)
- # shadow-cljs (32)
- # spacemacs (63)
- # test-check (16)
- # tools-deps (5)
- # vim (21)
So I've been struggling with this for a while and I can't seem to get my head around why my _TimeDisplay
component keeps remounting on prop change. It doesn't when I follow https://github.com/reagent-project/reagent/blob/master/examples/material-ui/src/example/core.cljs but as soon as I put the code to add :classes
into its own function it mounts.
(def with-custom-styles (withStyles #js{:padding #js{:padding 20}}))
(defn _TimeDisplay [_]
(r/create-class
{:component-did-mount #(print "Mounting _TimeDisplay")
:reagent-render
(fn [{:keys [classes format on-change value]}]
[Grid {:classes {:root (:padding classes)} :container? true}
[TextField {;:auto-focus? true
:default-value (.get (Moment value format) "hour")
:full-width? true
:label "Hour"
:margin "normal"
:on-change (set-time format on-change "hour" value)}]
[TextField {:default-value (.get (Moment value format) "minute")
:full-width? true
:label "Minute"
:margin "normal"
:on-change (set-time format on-change "minute" value)}]
[TextField {:default-value (.get (Moment value format) "second")
:full-width? true
:label "Second"
:margin "normal"
:on-change (set-time format on-change "second" value)}]])}))
(defn TimeDisplay [props]
(r/create-class
{:component-did-mount #(print "Mounting TimeDisplay")
:reagent-render
(fn [props]
[:> (with-custom-styles (r/reactify-component
(fn [{:keys [classes]}]
[_TimeDisplay
(update props :classes merge (js->clj classes :keywordize-keys true))])))])}))
@pcj my best guess is because reagent caches the reactify-component
call, but you are re-creating the function each render with (fn [{:keys [classes]}] ...
so each time it renders, reactify-component
creates a new React class, and then React compares that class to the instance that was previously rendered and detects it’s a new component and unmounts the old one, mounts the new one
Thanks for the help! So I changed the defn to def but it still mounts every single time so I think that i'm recreating that function with each render. I am calling TimeDisplay like :
:time [TimeDisplay {:format (:format props)
:on-change time-change
:value @*current-value*}]
within a condp.
I have a macro that automatically adds the withStyles hoc that looks something like this:
:time4 (with-styles {:padding {:padding 20}}
[_TimeDisplay {:format (:format props)
:on-change time-change
:value @*current-value*}])
which works. I don't mind doing it that way but I don't really like the programmer having to inject the classes every single time the component is used.also, I don’t htink you should be calling r/create-class
inside of a function either. how are you calling TimeDisplay
?
I think what you actually want is:
(def _TimeDisplay
(r/create-class
{:component-did-mount #(print "Mounting _TimeDisplay")
:reagent-render
(fn [{:keys [classes format on-change value]}]
[Grid {:classes {:root (:padding classes)} :container? true}
[TextField {;:auto-focus? true
:default-value (.get (Moment value format) "hour")
:full-width? true
:label "Hour"
:margin "normal"
:on-change (set-time format on-change "hour" value)}]
[TextField {:default-value (.get (Moment value format) "minute")
:full-width? true
:label "Minute"
:margin "normal"
:on-change (set-time format on-change "minute" value)}]
[TextField {:default-value (.get (Moment value format) "second")
:full-width? true
:label "Second"
:margin "normal"
:on-change (set-time format on-change "second" value)}]])}))
(def TimeDisplay
(r/create-class
{:component-did-mount #(print "Mounting TimeDisplay")
:reagent-render
(fn [props]
[:> (with-custom-styles (r/reactify-component
(fn [{:keys [classes]}]
[_TimeDisplay
(update props :classes merge (js->clj classes :keywordize-keys true))])))])}))