I added the following 13 lines of code:
(def app-history (atom [@app-state])) (add-watch app-state :history (fn [_ _ _ n] (when-not (= (last @app-history) n) (swap! app-history conj n)) (set! (.-innerHTML (.getElementById js/document "message")) (let [c (count @app-history)] (str c " Saved " (pluralize c "State")))))) (aset js/window "undo" (fn [e] (when (> (count @app-history) 1) (swap! app-history pop) (reset! app-state (last @app-history)))))
Again in Om we always have access to the entire app state so we just need to save it on every serious change in app state. Then undo is simply loading a previous snapshot. Because of immutable data structures React can re-render just as quickly going back in time as it does going forward in time. While it may appear that storing the app state like this would consume a lot of memory, it doesn't because ClojureScript data structures work via structural sharing.
Full source here.
Happy New Years!