Reference Cursors in Om
How to create a reference cursor
(def app-state
(atom {:items [{:text "cat"} {:text "dog"} {:text "bird"}]}))
(defn items []
(om/ref-cursor (:items (om/root-cursor app-state))))
Om
(simplified)
- Clojurescript framework based on React
- Application state is stored in a global atom
- ... usually as some sort of tree
- Components are functions from (parts of) that state to DOM elements
Cursors
- Selectors into the app state which are passed in to components
- Similar to lenses or zippers
-
Updates (transact!) are reflected in the global atom
Cursors
(motivation)
- Reusable components
- know nothing of the global state or their place in it
- Defines dependencies
- Component knows to re-render when data in its cursor is changed
Cursors
(problems)
- State for deeply nested cursors must be passed through each parent
- Parent components must know about all of their descendents
- Collaboration between components becomes difficult; shared data must be passed down from a common ancestor
Cursors
(workarounds)
- Core.async
- Component requests data from a global function and calls set-state! on itself
- Pub-sub channels
Reference Cursors
- New in 0.8.0, currently in beta
- Define global cursors which components can choose to observe
- Otherwise work just like regular cursors; updates (transact!) propagate to global atom
- Allow you to define a shared API to your application state which any component can access
The code
(def app-state
(atom {:items [{:text "cat"} {:text "dog"} {:text "bird"}]}))
(defn items []
(om/ref-cursor (:items (om/root-cursor app-state))))
(defn sub-view [{:keys [title]} owner]
(reify
om/IRender
(render [_]
(let [xs (om/observe owner (items))]
(dom/div nil
(dom/h2 nil title)
(apply dom/ul nil
(map #(dom/li nil (:text %)) xs)))))))
References
Reference Cursors in Om
By Brad Peterson
Reference Cursors in Om
- 1,359