2016-05-13 80 views
5

这似乎并不被发生的Quick Start tutorial说:为什么Om Next组件在状态更改时不重新呈现?

在庵下一个应用程序状态的变化是由调解管理。协调器接受新颖性,将其合并到应用程序状态中, 根据其声明的查询找到所有受影响的组件,并且 计划重新呈现。

当我改变选择框时,mutate函数更新状态,但App组件的render函数从不执行。我可以在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 

如果我(swap! app-state update-in [:current-topic] (fn [] "b"))更新从REPL状态则APP的渲染功能无法执行。这里是控制台输出:

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

回答

1

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

你的UI应用程序可能会再看看这样的:

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

IQuery绝对是更好的解决方案,但我仍然有同样的问题,像你这样的。这种解决方法现在在我的项目中运行,我一定会再次看看IQuery

编辑

本教程大约Components, Identity and Normalization说明你要做的时候才需要更新UI的东西。这导致了更习惯的解决方案。

0

Om为了避免不必要地调用读取函数并避免无用的重新呈现,接下来不愿意为了性能原因触发重新读取查询。

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

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

要指定该查询 :current-topic组件应该重新渲染(并呼吁相关的读取功能),可以在办理向量的末尾提供这些键
相关问题