Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Demonstrating how ref-cursors + state can combine to cause double-renders
(ns om.repro.state-and-ref-cursors
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]))
(defonce app-state (atom {:foo {}}))
(defn animating-component [app owner]
(reify
om/IDidUpdate
(did-update [_ _ _]
(let [duration (- (js/Date.now)
(om/get-state owner :start-time))]
(when (<= duration 2000)
(om/set-state! owner :left
(-> (- 1 (/ duration 2000))
(* 200)
js/Math.round
(max 0)
(min 200))))))
om/IRenderState
(render-state [_ {:keys [start-time left]}]
(let [_ (om/observe owner (-> (om/root-cursor app-state)
:foo
om/ref-cursor))]
(when start-time
(println "Render!" (str (- (js/Date.now) start-time) "ms")))
(dom/div nil
(dom/button #js {:onClick #(om/set-state! owner :start-time
(js/Date.now))}
"Animate!")
(dom/div #js {:style #js {:position "relative"
:width 200
:height 200
:backgroundColor "blue"
:left left}}))))))
;; RESULT: Two renders per animation frame, e.g.
;; ...
;; Render! 62ms
;; Render! 64ms
;; Render! 79ms
;; Render! 81ms
;; Render! 96ms
;; Render! 100ms
;; Render! 112ms
;; Render! 114ms
;; ...
;;
;; If you remove the `om/observe`, the issue goes away.
(defonce add-divs
(doseq [id ["animating-component"]
:let [el (js/document.createElement "div")]]
(.setAttribute el "id" id)
(js/document.body.appendChild el)))
(defn render []
(om/root animating-component app-state {:target (js/document.getElementById "animating-component")}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.