How can I write rewritable asynchronous code using Om + Figwheel + core.async?

I would like to write something like a clock application. A state is a number that increases several times. One way to do this can be seen here.

(ns chest-example.core
  (:require [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true]
            [cljs.core.async :as async])
  (:require-macros [cljs.core.async.macros :refer [go]]))

(defonce app-state (atom {:time 0}))

(defn clock-view [data owner]
  (reify
    om/IRender
    (render [_]
      (dom/div nil (pr-str data)))))

(go (while true
  (async/<! (async/timeout 1000))
  (om/transact! (om/root-cursor app-state) :time inc)))

(defn main []
  (om/root
    clock-view
    app-state
    { :target (. js/document (getElementById "clock"))}))

The problem with this is that this is not reloadable code. As soon as I update the code using the fig wheel, the increment becomes faster, as there are several things that update the state.

I tried experimenting with different ideas (mostly by creating different components for the go operator’s own code), but I couldn’t come up with something that would work.

Does anyone have a neat solution for this, or should I just stick with it during development?

+4
source
2

goroutine, . - close!, goroutine:

(ns myproject.core
  ;; imports
  )

(def my-goroutine
  (go-loop []
    (when (async/<! (async/timeout 1000))
      (om/transact! (om/root-cursor app-state) :time inc)
      (recur)))))

;; put in your on-reload function for figwheel
(defn on-reload []
  (async/close! my-goroutine))

goroutine, , , ( figwheel :on-jsload config).

;; project.clj
(defproject ;; ...
  :figwheel {:on-jsload "myproject.core/on-reload"}
)

, . golang / . core.async goroutines.

+2

Ok. - . , , , , , . , . , , . , .

! , . "" DOM, : ! .

, , , , , .

(defn clock-controller [state owner]
  (reify
    om/IInitState
      (init-state [_]
        {:channel (async/chan)})
    om/IWillMount
    (will-mount [_]
      (go (loop []
        (let [c (om/get-state owner :channel)
              [v ch] (async/alts! [(async/timeout 1000) c])]
          (if (= v :killed)
            nil
            (do
              (om/transact! state :time (fn [x] (+ x 1)))
              (recur)))))))
    om/IWillUnmount
    (will-unmount [_]
      (let [c (om/get-state owner :channel)]
        (go
          (async/>! c :killed)
          (async/close! c))))
    om/IRender
    (render [_])))
0
source

All Articles