Mic*_*ent 6 clojure clojurescript core.async om
当我发表评论时,为什么子组件中的计数器更新正常
(om/update-state! owner :clicked not)
Run Code Online (Sandbox Code Playgroud)
而不是当我在下面的代码中的父组件中取消注释它?单击按钮更新计数器.
我想要实现的是一个pub/sub机制,因此组件可以以分离的方式交换消息.
您可以通过以下方式创建一个新项目来复制它:
lein new mies-om om-channel-test
Run Code Online (Sandbox Code Playgroud)
然后用下面的代码替换core.cljs并运行
lein cljsbuild auto
Run Code Online (Sandbox Code Playgroud)
在现代浏览器中访问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}})
Run Code Online (Sandbox Code Playgroud)
在https://groups.google.com/forum/#!topic/clojurescript/5rCTfnulNXI上回答。
当第 41 行未注释时,似乎会发生以下情况:
父组件的状态改变了
om/react“遍历”父级渲染中的组件树以查看应该更新哪些内容
第 45 行om/buildfor the child 组件发现子组件已经存在,因此没有创建或安装新组件。
但是,第 45 行上的“运行”/调用创建了对through inom/build的新订阅event-pub:subscriber/:create-subscriber{:init-state ...}
不会创建一个新组件来创建一个循环来从这个新订阅者通道消费(om/will-mount第 22 行没有调用新组件)
现在event-pub有两个订阅者,但只有一个go-loop订阅者从频道消费。上的酒吧:event-ch将被封锁 [1] [2]
页面上的奇怪现象
{:init-state ...}似乎你不应该在传递给 时产生副作用om/build。相反,通过将 传递event-pub给子组件:init-state,并创建子 chan 以及go-loop从中使用的 。
[1] http://clojure.github.io/core.async/#clojure.core.async/pub “每个项目都并行且同步地分发给所有子项目,即每个子项目必须在分发下一个项目之前接受。使用缓冲/窗口来防止慢速潜艇拖住酒吧。”
[2] 尝试在第 57 行的 chan 中进行缓冲,以查看单击几次后此行为的变化