Core.async pub / sub behaves oddly in Om (clojurescript)

Why the counter in the child component is updated when I comment

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

but not when I uncomment it in the parent component in the code below? The counter is updated by pressing a button.

What I'm trying to accomplish is the pub / sub mechanism so that the components can exchange messages separately.

You can play it by creating a new project with

 lein new mies-om om-channel-test 

Then replace core.cljs with the code below and run

 lein cljsbuild auto 

Go to the index.html page in a modern browser (e.g. latest Chrome).

Code:

 (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}}) 
+6
source share
1 answer

Answered at https://groups.google.com/forum/#!topic/clojurescript/5rCTfnulNXI .

If line 41 is uncommented, the following will happen:

  • The state of parent components has changed

  • om/react "walks" the component tree in the parent render to see what needs to be updated

  • line 45 with om/build for the child component reveals that the child component already exists, so the new component has not been created or installed.

  • However, the β€œlaunch” / call to om/build on line 45 created a new event-pub subscription via :subscriber/:create-subscriber in {:init-state ...}

  • A new component will not be created that would create a cycle loop that will be consumed from this new subscriber channel (there is no om/will-mount call for the new component from line 22)

  • Now event-pub has two subscribers, but only one go-loop , which consumes from the channel. Pub on :event-ch block [1] [2]

  • Oddity on the page

It seems you shouldn't have any side effects in {:init-state ...} passed to om/build . Instead, pass event-pub child component via :init-state and create an additional chan along with go-loop to consume it.

[1] http://clojure.imtqy.com/core.async/#clojure.core.async/pub "Each item is distributed across all submarines in parallel and synchronously, that is, each sub must be received before the next item is sent "use buffering / window processing to prevent slow submarines from raising the pub."

[2] Play buffered chan on line 57 to see this behavior change in a couple of clicks.

0
source

Source: https://habr.com/ru/post/975495/


All Articles