这似乎不会发生,因为Quick Start tutorial说:
在Om Next应用程序中,状态更改由协调程序管理。该 reconciler接受新颖性,将其合并到应用程序状态, 根据声明的查询查找所有受影响的组件 安排重新渲染。
当我更改选择框时,mutate函数会更新状态,但App组件的渲染函数永远不会执行。我可以在REPL中看到@ app-state状态已经改变,我从未在App的渲染功能中看到控制台中的输出。这就是我在控制台中看到的全部内容:
[1955.847s] [om.next] transacted '[(om-tutorial.core/switch-topic {:name "b"})], #uuid "c3ba6741-81ea-4cbb-8db1-e86eec26b540"
"read :default" :topics
如果我使用(swap! app-state update-in [:current-topic] (fn [] "b"))
从REPL更新状态,则应用程序的渲染功能会执行。这是控制台输出:
"read :default" :topics
"read :default" :current-topic
"App om-props " {:topics [{:name "a"} {:name "b"}], :current-topic "b"}
"Topics om-props " {:topics [{:name "a"} {:name "b"}]}
以下是完整代码:
(ns om-tutorial.core
(:require [goog.dom :as gdom]
[om.next :as om :refer-macros [defui]]
[om.dom :as dom]))
(enable-console-print!)
(def app-state (atom {:current-topic "a" :topics [{:name "a"} {:name "b"}]}))
(defmulti read (fn [env key params] key))
(defmethod read :default
[{:keys [state] :as env} key params]
(prn "read :default" key)
(let [st @state]
(if-let [value (st key)]
{:value value}
{:value :not-found})))
(defmulti mutate om/dispatch)
(defmethod mutate 'om-tutorial.core/switch-topic
[{:keys [state]} _ {:keys [name]}]
{:action
(fn []
(swap! state update-in
[:current-topic]
#(identity name)))})
(defui Topics
static om/IQuery
(query [this]
[:topics])
Object
(render [this]
(let [{:keys [topics] :as props} (om/props this)]
(prn "Topics om-props " props)
(apply dom/select #js {:id "topics"
:onChange
(fn [e]
(om/transact! this
`[(switch-topic ~{:name (.. e -target -value)})]))}
(map #(dom/option nil (:name %)) topics)))))
(def topics-view (om/factory Topics))
(defui App
static om/IQuery
(query [this]
'[:topics :current-topic])
Object
(render [this]
(let [{:keys [topics current-topic] :as om-props} (om/props this)]
(prn "App om-props " om-props)
(dom/div nil
(topics-view {:topics topics})
(dom/h3 nil current-topic)))))
(def reconciler
(om/reconciler
{:state app-state
:parser (om/parser {:read read :mutate mutate})}))
(om/add-root! reconciler App (gdom/getElement "app"))
这是project.clj文件:
(defproject om-tutorial "0.1.0-SNAPSHOT"
:description "My first Om program!"
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.omcljs/om "1.0.0-alpha24"]
[figwheel-sidecar "0.5.0-SNAPSHOT" :scope "test"]])
答案 0 :(得分:2)
我在我的应用程序中遇到了同样的问题并找到了解决方法(尽管这可能不是最佳解决方案)。您可以通过传递父组件的om属性来构建组件。
你的ui应用程序可能会是这样的:
(defui App
Object
(render [this]
(dom/div nil (topics-view (om/props this)))))
IQuery
绝对是更好的解决方案,但我仍然有像你一样的问题。此解决方法暂时适用于我的项目,我一定会再次查看IQuery
。
修改强>
关于Components, Identity and Normalization的教程解释了在必要时更新UI时必须执行的操作。这导致更惯用的解决方案。
答案 1 :(得分:0)
Om Next不愿意出于性能原因触发对查询的重新读取,以避免不必要地调用它们的读取函数并避免无用的重新渲染。要指定查询2017-05-28 08:00:00.995 appName[6714:472740] 08:00:00.960 WARNING: 40: ERROR: couldn't get default input device, ID = 0, err = 0!
2017-05-28 08:00:00.996 appName[6714:472740] 08:00:00.996 WARNING: 40: ERROR: couldn't get default output device, ID = 0, err = 0!
2017-05-28 08:00:00.996 appName[6714:472740] 08:00:00.996 ERROR: 708: Error finding valid input or output devices!
2017-05-28 08:00:00.997 appName[6714:472740] 08:00:00.997 ERROR: 312: error -66680
2017-05-28 08:00:00.997 appName[6714:472740] 08:00:00.997 ERROR: 130: * * * NULL AQIONode object
2017-05-28 08:00:00.997 appName[6714:472740] 08:00:00.997 ERROR: 753: Can't make UISound Renderer
2017-05-28 08:00:01.048 appName[6714:472434] 08:00:01.048 ERROR: 312: error -66680
2017-05-28 08:00:01.048 appName[6714:472434] 08:00:01.048 ERROR: >aq> 1627: failed (-66680); will stop (11025/0 frames)
pause
的组件应该重新呈现(以及调用相关的读取函数),您可以在事务向量的末尾提供这些键:
:current-topic
参考:https://github.com/omcljs/om/wiki/Documentation-(om.next)#transact