5

正如快速入门教程所说,这似乎没有发生:

在 Om Next 中,应用程序状态更改由协调器管理。协调器接受新奇事物,将其合并到应用程序状态中,根据声明的查询找到所有受影响的组件,并安排重新渲染。

当我更改选择框时,mutate 函数会更新状态,但 App 组件的渲染函数永远不会执行。我可以在 REPL 中使用@app-state 看到状态已更改,并且我从未在应用程序的渲染函数中看到来自 prn 的控制台中的输出。这就是我在控制台中看到的全部内容:

 [1955.847s] [om.next] transacted '[(om-tutorial.core/switch-topic {:name "b"})], #uuid "c3ba6741-81ea-4cbb-8db1-e86eec26b540"
"read :default" :topics

如果我从 REPL 更新状态,(swap! app-state update-in [:current-topic] (fn [] "b"))则应用程序的渲染函数会执行。这是控制台输出:

"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"]])
4

2 回答 2

2

我在我的应用程序中遇到了同样的问题并找到了解决方法(尽管这可能不是最好的解决方案)。您可以通过传递父组件的 om 属性来构造您的组件。

您的 ui 应用程序可能看起来像这样:

(defui App
  Object
  (render [this]
          (dom/div nil (topics-view (om/props this)))))

IQuery绝对是更好的解决方案,但我仍然有和你一样的问题。这个解决方法目前在我的项目中有效,我一定会再看看IQuery

编辑

关于组件、身份和规范化的教程解释了在必要时更新 UI 必须做的事情。这导致了更惯用的解决方案。

于 2016-08-26T12:21:41.250 回答
0

出于性能原因,Om Next 不愿意触发对查询的重新读取,以避免不必要地为它们调用读取函数并避免无用的重新渲染。要指定查询的组件:current-topic应该重新呈现(以及调用的相关读取函数),您可以在事务向量的末尾提供这些键:

(om/transact! this
  `[(switch-topic ~{:name (.. e -target -value)})
    :current-topic])

参考:https ://github.com/omcljs/om/wiki/Documentation-(om.next)#transact

于 2017-05-28T15:09:02.873 回答