core.async pub / sub在Om中表现奇数(clojurescript)

时间:2014-09-18 16:09:44

标签: clojure clojurescript core.async om

为什么我发表评论时,子组件中的计数器更新正常

(om/update-state! owner :clicked not) 

而不是在我在下面的代码中的父组件中取消注释它? 单击按钮即可更新计数器。

我想要实现的是一个发布/订阅机制,因此组件可以以分离的方式交换消息。

您可以通过以下方式创建一个新项目来复制它:

lein new mies-om om-channel-test

然后用下面的代码替换core.cljs并运行

lein cljsbuild auto

在现代浏览器中访问index.html页面(例如最新的Chrome)。

代码:

(ns om-channel-test.core
  (:require-macros [cljs.core.async.macros :refer (go)])
  (:require [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true]
            [cljs.core.async :refer [chan pub <! sub >! timeout put!]]))

(enable-console-print!)

(def app-state (atom {:text "Hello world!"}))

(def event-ch (chan))

(def event-pub
  (pub event-ch #(:topic %)))

(defn child [cursor owner]
  (reify
    om/IInitState
    (init-state [_]
      {:counter 0})
    om/IWillMount
    (will-mount [_]
      (go (loop [] (<! (om/get-state owner :subscriber))
                (println "message received")
                (om/update-state! owner :counter inc)
                (recur))))
    om/IRender
    (render [_]
      (println "rendering child")
      (dom/p nil (om/get-state owner :counter)))
    om/IWillUnmount
    (will-unmount [_]
      (println "unmount"))))

(defn parent [cursor owner]
  (om/component
   (println "rendering parent")
   (dom/div nil
            (dom/button #js {:onClick
                             #(do
                                #_(om/update-state! owner :clicked not)
                                (go (>! event-ch {:topic :wizard
                                                  :message "hello"})))}
                        "Click")
            (om/build child
                      cursor
                      {:init-state
                       {:subscriber
                        ((om/get-shared owner :create-subscriber) :wizard)}}))))

(om/root
 parent
 app-state
 {:target (. js/document (getElementById "app"))
  :shared {:create-subscriber (fn [topic]
                                (sub event-pub
                                     topic (chan)))
           :event-ch event-ch}})

1 个答案:

答案 0 :(得分:0)

回答https://groups.google.com/forum/#!topic/clojurescript/5rCTfnulNXI

如果第41行未注释,则会发生以下情况:

  1. 父组件的状态已更改

  2. om/react“遍历”父级渲染中的组件树以查看应更新的内容

  3. 子行为om/build的第45行
  4. 发现子组件已经存在,因此没有创建或安装新组件。

  5. 但是,第45行的“正在运行”/致电om/buildevent-pub

    中创建了:subscriber/:create-subscriber{:init-state ...}的新订阅
  6. 将不会创建一个新组件来创建从这个新订阅者频道使用的循环(对于来自第22行的新组件,没有调用om/will-mount

  7. 现在event-pub有两个订阅者,但只有一个go-loop来自频道。 :event-ch上的酒吧将阻止[1] [2]

  8. 页面上的怪异

  9. 似乎你不应该在传递给{:init-state ...}的{​​{1}}中产生副作用。而是通过om/buildevent-pub传递给子组件,并与:init-state一起创建子chan以从中使用。

    [1] http://clojure.github.io/core.async/#clojure.core.async/pub “每个项目并行和同步分配给所有潜艇, 即每个子必须在下一个项目分发之前接受。使用 缓冲/开窗以防止缓慢的潜水员阻止酒吧。“

    [2]在第57行的chan中进行缓冲,以便在几次点击中看到此行为更改