Skip to content

Instantly share code, notes, and snippets.

@pesterhazy
Last active September 4, 2017 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pesterhazy/36b56d1bd8b424abef81adbb5a392d93 to your computer and use it in GitHub Desktop.
Save pesterhazy/36b56d1bd8b424abef81adbb5a392d93 to your computer and use it in GitHub Desktop.
Reagent, anonymous functions and props
(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)
@worrel
Copy link

worrel commented Apr 17, 2017

ah-ha, i just noticed this myself today in a deeply-layered component tree, the form-2 solution worked for me. Thanks!

@Olical
Copy link

Olical commented Sep 4, 2017

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