Секретарь маршрутизации, Ident Query в om.next
Я предрежу этот вопрос, сказав, что я все еще очень новичок, когда дело доходит до Clojure/Script, поэтому, помимо очень острого вопроса, я буду давать какие-либо общие отзывы о стиле, использование будет с благодарностью.
Я создавал очень простое приложение с помощью om.next. Для маршрутизации на стороне клиента я решил использовать секретарь. Мое приложение отображает список элементов, и предполагается, что при нажатии на один из этих элементов вы можете просмотреть детали. Реализация в настоящее время осуществляется с помощью простого href
на теге привязки (например, href
может выглядеть как /items/1
, где 1
это id
). Это отчасти потому, что вы должны иметь возможность перейти к URL-адресу сведений напрямую, чтобы увидеть то же представление. Как бы просто это ни звучало, я не могу на всю жизнь заставить работать так, как хотелось бы.
Во-первых, давайте посмотрим на существенную конфигурацию для примирителя (для краткости я удалил детали реализации компонента render
на протяжении)...
(def init-data {:items [{:id 1
:title "stack overflow"
:description "hello, world."
:photos []}
{:id 2
:title "foo"
:description "bar"
:photos []}]})
(defui ListItem
static om/Ident
(ident [this {:keys [id]}]
[:items/by-id id])
static om/IQuery
(query [this]
[:id :title :description :photos]))
(defui Items
static om/IQuery
(query [this]
[{:items (om/get-query ListItem)}]))
(defmulti read om/dispatch)
(defmethod read :items
[{:keys [state query] :as env} key _]
(let [st @state]
{:value (om/db->tree query (get st key) st)}))
(def app-state (atom (om/tree->db Items init-data true)))
(def reconciler
(om/reconciler {:parser (om/parser {:read read})
:state app-state}))
Проницательный увидит, что я пытаюсь мыслить ссылками, и это, похоже, работает, как я и ожидал. Когда я добавляю этот компонент и пытаюсь использовать его за секретным маршрутом, все рушится...
; I tried other approaches, they failed too
(defui Item
static om/IQueryParams
(params [this]
{:id :not-found})
static om/IQuery
(query [this]
'[[:items/by-id ?id]]))
(defn render-component [component]
(let [app (gdom/getElement "app")]
(doto reconciler
(om/remove-root! app)
(om/add-root! component app)))))
(defroute item-path "/items/:id" [id]
(let [component Item]
; this is already less than ideal, as we know the id
; before the first render of the component
(render-component component)
(om/set-query! (om/class->any reconciler component)
{:id (js/parseInt id)})))
Пример моего Item
компонент не получает надлежащее состояние в props
как указано в запросе (он получает все app-state
). Что меня больше всего удивляет, так это то, что если я выполню тот же запрос app-state
вручную в REPL я получаю правильный набор данных обратно...
(get-in @app-state [:items/by-id 1])
; {:id 1, :title "stack overflow", :description "hello, world.", :photos []}
Единственное, что до сих пор работало для меня, это обойти реконсилятор (сам создавая экземпляр компонента), передав значение запроса из app-state
как реквизит. Но это означает, что я не могу изменить состояние с помощью примирителя, что является новой ужасной морщинкой в грязной и неопрятной головоломке.
Что мне здесь не хватает? Хотя у меня много идей, больше всего меня подозрительно вызывает инициализация app-state
с помощью om/tree->db
,