Last active
September 4, 2017 14:47
-
-
Save pesterhazy/36b56d1bd8b424abef81adbb5a392d93 to your computer and use it in GitHub Desktop.
Reagent, anonymous functions and props
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns test.reagent | |
(:require [reagent.core :as r])) | |
;; Reagent, anonymous functions and props | |
;; Demonstrate that a reagent component will rererender | |
;; each time when its enclosing component updates *if* | |
;; one if its props is an anonymous fn. | |
;; | |
;; Note that the DOM is not update in each case, as the | |
;; generated React elements don't change. But for outer1, | |
;; but not for outer2, the render fn inner is called each | |
;; time you click the button. | |
;; The problem is apparent in outer1. Two ways to get around | |
;; this are outer2 (using a def) and outer3 (using a Form2 comp) | |
(defn inner [] | |
(let [counter (atom 0)] | |
(fn [name f] | |
(println "render" name "count:" (swap! counter inc)) | |
[:div "hello"]))) | |
;; outer1 rerenders when clickin the button | |
;; because its second prop is an anonymous fn. | |
(defn outer1 [num] | |
[inner :outer1 (fn [] (println "bar"))]) | |
;; outer2 doesn't rerender because its second | |
;; prop is a named fn that doesn't change | |
(defn foo [] | |
(println "foo")) | |
(defn outer2 [num] | |
[inner :outer2 foo]) | |
;; outer3 captures the anon fn in a let of a | |
;; Form-2 component, also avoid rerenders. | |
(defn outer3 [] | |
(let [cb (fn [] (println "bar"))] | |
(fn [num] | |
[inner :outer3 cb]))) | |
(def num (r/atom 0)) | |
(defn render [] | |
[:div | |
[:h1 "Reagent Test"] | |
[:h2 "outer1"] | |
[outer1 @num] | |
[:h2 "outer2"] | |
[outer2 @num] | |
[:h2 "outer3"] | |
[outer3 @num] | |
[:div {:style {:margin-top 20}}] | |
[:button {:on-click #(swap! num inc)} (str "Count: " @num)]]) | |
(r/render [render] js/klipse-container) |
ah-ha, i just noticed this myself today in a deeply-layered component tree, the form-2 solution worked for me. Thanks!
I've been thinking about this recently, and you could also get around it in some cases with (def memtial (memoize partial))
where outer1
would become:
(defn outer1 [num]
[inner :outer1 (memtial println "bar")])
It shares fn references as long as the arguments are the same. It's not a completely general solution, but could come in handy. Also not sure about the name...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live demo at http://app.klipse.tech/?cljs_in.gist=pesterhazy/36b56d1bd8b424abef81adbb5a392d93&container=1