Skip to content

Instantly share code, notes, and snippets.

@mrcslws
Last active August 29, 2015 14:08
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 mrcslws/ed7d78d433674c5ab08f to your computer and use it in GitHub Desktop.
Save mrcslws/ed7d78d433674c5ab08f to your computer and use it in GitHub Desktop.
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