Skip to content

Instantly share code, notes, and snippets.

@mrcslws mrcslws/om-stale-cursors
Last active Aug 29, 2015

Embed
What would you like to do?
Demonstration that Om cursors can quietly dereference to someone else's path. If you quickly move your mouse over this list of names, the assert fails, because you switch up the app-state indices and then cause another event before a render updates the paths.
(ns explore-om.stalecursors
(:require-macros [cljs.core.async.macros :refer [go-loop]])
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[cljs.core.async :refer [put! chan <!]]))
;;;
;;; Sample code from https://github.com/swannodette/om/wiki/Basic-Tutorial
;;;
(def app-state
(atom
{:contacts
[{:first "Ben" :last "Bitdiddle"
:email "benb@mit.edu"}
{:first "Alyssa" :middle-initial "P" :last "Hacker"
:email "aphacker@mit.edu"}
{:first "Eva" :middle "Lu" :last "Ator"
:email "eval@mit.edu"}
{:first "Louis" :last "Reasoner"
:email "prolog@mit.edu"}
{:first "Cy" :middle-initial "D" :last "Effect"
:email "bugs@mit.edu"}
{:first "Lem" :middle-initial "E" :last "Tweakit"
:email "morebugs@mit.edu"}]}))
(defn middle-name [{:keys [middle middle-initial]}]
(cond
middle (str " " middle)
middle-initial (str " " middle-initial ".")))
(defn display-name [{:keys [first last] :as contact}]
(str last ", " first (middle-name contact)))
;;;
;;; When you move the mouse over a contact, have it "flee".
;;; Also, sanity-check that the cursor is returning the contact
;;; that it's supposed to be referring to.
;;;
(defn contact-view [contact owner]
(reify
om/IRenderState
(render-state [_ {:keys [flee]}]
(let [firstname (:first contact)]
(dom/li nil
(dom/span
#js {:onMouseMove
(fn []
(assert (= firstname (:first @contact))
(str "Expected: " firstname
" Actual: " (:first @contact)))
(put! flee @contact))}
(display-name contact))
(dom/button nil "These")
(dom/button nil "buttons")
(dom/button nil "make")
(dom/button nil "the")
(dom/button nil "repro")
(dom/button nil "more")
(dom/button nil "reliable."))))))
;;;
;;; When a contact flees, move it to the end of the list.
;;;
(defn contacts-view [app owner]
(reify
om/IInitState
(init-state [_]
{:flee (chan)})
om/IWillMount
(will-mount [_]
(let [flee (om/get-state owner :flee)]
(go-loop []
(let [contact (<! flee)]
(om/transact! app :contacts
(fn [xs] (conj (vec (remove #(= contact %) xs))
contact))))
(recur))))
om/IRenderState
(render-state [this state]
(dom/div nil
(dom/h2 nil "Contact list")
(apply dom/ul nil
(om/build-all contact-view (:contacts app)
{:init-state state}))))))
(defn main []
(om/root contacts-view app-state
{:target (. js/document (getElementById "contacts"))}))
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.