4

時計アプリのようなものを書きたいと思います。状態は基本的に、繰り返しインクリメントされる数値です。その方法の 1 つをここで見ることができます。

(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"))}))

これがリロード可能なコードではないという問題があります。fig wheel を使用してコードを更新すると、状態を更新するものがいくつかあるため、インクリメントが速くなります。

さまざまなアイデア (基本的には、go ステートメント コードを所有するさまざまなコンポーネントを作成する) を試してみましたが、機能するものを思いつくことができませんでした。

誰かがこれに対するきちんとした解決策を持っていますか、それとも開発中にそれに固執する必要がありますか?

4

2 に答える 2

0

Ok。提案を読んだ後、私は自分で何かを実装することに挑戦しました。これが最善の解決策であるとは言えませんので、フィードバックを歓迎しますが、うまくいくようです。基本的に、チャールズが提案したことを行います。コンポーネント自体が追加または削除されたときのコールバックを持つコンポーネント内にラップしました。どうせ figwheel の onload フックでこれを行うのは難しいと思います。

アルツ!2 つのチャネルから入力を取得できるように使用されます。コンポーネントが DOM から「削除」されると、alts に :killed シグナルが送信されます。ループを終了します。

クロックコントローラーは、基本的にはクロックを刻み続け、アプリの状態を更新するためだけに存在するものをレンダリングしません。これは、カーソルを介して任意の他のコンポーネントによって消費される可能性があります。

(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 [_])))
于 2015-05-21T02:55:14.030 に答える