Ошибка: нет запросов для пути к компоненту?
Я пробую om.next, пытаясь расширить пример, приведенный в разделе " Компоненты, идентичность и нормализация".
Код в приведенном выше примере содержит два списка, которые поддерживаются данными в двух разных путях в состоянии. В примере показано, как нормализация данных позволяет легко обновлять нормализованные объекты, встречающиеся в разных представлениях. В приведенном ниже коде я удалил второй список в приведенном ниже примере, поскольку поведение все равно проявляется.
Рабочий пример
Пример ниже работает и показывает:
Список А
- Джон, очки: 4 +
- Мария, очков: 0 +
- Боб, очков: 0 +
где + это кнопка, которая увеличивает точку для человека.
(ns ui.core
(:require [om.next :as om :refer-macros [defui]]
[om.dom :as dom]
[goog.dom :as gdom]))
(def init-data
{:list/one [{:name "John" :points 0}
{:name "Mary" :points 0}
{:name "Bob" :points 0}]})
;; -----------------------------------------------------------------------------
;; Parsing
(defmulti read om/dispatch)
(defn get-people [state key]
(let [st @state]
(into [] (map #(get-in st %)) (get st key))))
(defmethod read :list/one
[{:keys [state] :as env} key params]
{:value (get-people state key)})
(defmulti mutate om/dispatch)
(defmethod mutate 'points/increment
[{:keys [state]} _ {:keys [name]}]
{:action
(fn []
(swap! state update-in
[:person/by-name name :points]
inc))})
;; -----------------------------------------------------------------------------
;; Components
(defui Person
static om/Ident
(ident [this {:keys [name]}] [:person/by-name name])
static om/IQuery
(query [this] '[:name :points :age])
Object
(render [this]
(let [{:keys [points name] :as props} (om/props this)]
(dom/li nil
(dom/label nil (str name ", points: " points))
(dom/button
#js {:onClick
(fn [e]
(om/transact! this
`[(points/increment ~props)]))}
"+")))))
(def person (om/factory Person {:keyfn :name}))
(defui ListView
Object
(render [this]
(let [list (om/props this)]
(apply dom/ul nil
(map person list)))))
(def list-view (om/factory ListView {:key-fn ffirst}))
(defui RootView
static om/IQuery
(query [this]
(let [subquery (om/get-query Person)]
`[{:list/one ~subquery}]))
Object
(render [this]
(let [{:keys [list/one]} (om/props this)]
(apply dom/div nil
[
(dom/h2 nil "List A")
(list-view one)
]))))
(def rootview (om/factory RootView))
;; wrapping the Root in another root (this fails)
(defui AnotherRoot
static om/IQuery
(query [this] `[~@(om/get-query RootView)])
Object
(render
[this]
(dom/div nil
(rootview (om/props this)))))
(def reconciler
(om/reconciler
{:state init-data
:parser (om/parser {:read read :mutate mutate}) }))
(om/add-root! reconciler RootView (gdom/getElement "app"))
Проблема: использование AnotherRoot в качестве корневого компонента
Однако, когда я изменяю RootView в последнем ряду на AnotherRoot, например:
(om/add-root! reconciler AnotherRoot (gdom/getElement "app"))
пользовательский интерфейс по-прежнему отображается, но при нажатии кнопки возникает следующая ошибка:
Error: No queries exist for component path
(ui.core/AnotherRoot ui.core/RootView ui.core/Person)
Ошибка происходит от ( next.cljc: 1916)
Я не понимаю ошибку. Запрос от AnotherRoot
возвращает тот же запрос, что и RootView
(однако, вы сразу же получите предупреждение при возврате запроса - что имеет смысл), но при этом компилятор, похоже, не сможет выяснить, как повторно визуализировать компонент при изменении состояния приложения.
Соответствующие зависимости должны быть:
[[org.clojure/clojure "1.9.0-alpha14"]
[org.clojure/clojurescript "1.9.473"]
[figwheel-sidecar "0.5.9"]
[org.omcljs/om "1.0.0-alpha47"]]
Вопрос
Каков общий способ создания вложенных компонентов в om.next?