6

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

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

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

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

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

lein new mies-om om-channel-test

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

lein cljsbuild auto

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

编码:

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

1 回答 1

0

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

在第 41 行未注释的情况下,似乎会发生以下情况:

  1. 父组件状态改变

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

  3. 在第 45 行 with om/buildfor the child component 发现子组件已经存在,因此没有创建或安装新组件。

  4. 但是,第 45 行的“运行”/调用创建了om/build一个新订阅event-pub:subscriber/:create-subscriber{:init-state ...}

  5. 将不会创建一个新组件来创建一个从这个新订阅者频道消费的循环(om/will-mount第 22 行没有调用新组件)

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

  7. 页面上的怪异

{:init-state ...}似乎你不应该在传递给的副作用om/build。而是将 传递event-pub给子组件,:init-state并创建子 chan 以及go-loop从中消费。

[1] http://clojure.github.io/core.async/#clojure.core.async/pub "每个项目被并行同步分发给所有的subs,即每个sub必须在下一个item被分发之前接受。使用缓冲/窗口来防止慢速潜艇阻塞酒吧。”

[2] 在第 57 行的 chan 中进行缓冲,单击几下即可查看此行为的变化

于 2016-09-27T10:44:43.420 回答