ClojureScript, Om и Core.async: как правильно обрабатывать события
Я посмотрел, как использовать Om для богатого дизайна веб-сайта клиента. Это также мой первый раз, используя core.async. Чтение учебника https://github.com/swannodette/om/wiki/Basic-Tutorial Я видел использование канала core.async для обработки операции удаления (в отличие от выполнения всей работы в обработчике). У меня создалось впечатление, что использование этого канала для удаления было просто сделано, потому что обратный вызов delete был объявлен в области, где у вас есть указатель на уровне элемента, где вы действительно хотите манипулировать списком, содержащим этот элемент.
Чтобы получить больше информации о каналах, я видел, как Rich Hickey говорил http://www.infoq.com/presentations/clojure-core-async, где он объясняет, как неплохо использовать каналы для получения логики приложения вне события -callbacks. Это заставило меня задуматься, действительно ли цель канала удаления в учебнике заключалась в том, чтобы показать этот способ структурирования приложения. Если да,
-
Каковы наилучшие методы, связанные с этим шаблоном?
-
Следует ли создавать отдельные каналы для всех видов событий? То есть Если я добавлю контроллер для создания нового события, могу ли я создать новый канал для создания объектов, который затем используется для того, чтобы объекты добавлялись в глобальное состояние в другом месте приложения?
-
Допустим, у меня есть список элементов, и у одного элемента есть подробный/сжатый флаг состояния. Если detailed?
- true
, он отобразит больше информации, если detailed?
- false
, будет отображаться меньше информации. Я связал событие on-click, которое использует om/transact!
в курсоре (являющийся представлением элемента списка в глобальном объекте состояния).
(let [toggle-detail-handler
(fn [e]
(om/transact! (get-in myitem [:state])
#(conj % {:detailed? (not (:detailed? %))})))]
(html [:li {:on-click toggle-detail-handler}
"..." ]))
Я понимаю, что это может быть очень сжатый фрагмент, в котором общая польза использования каналов как средства отделить событие обратного вызова от изменений логической логики вначале не стоит усилий, но общие преимущества с более сложными примерами перевешивают это. Но, с другой стороны, введение дополнительного канала для такого подробного, но не подробного переключения, похоже, добавляет достаточную нагрузку на исходный код.
Было бы здорово, если бы вы могли дать некоторые подсказки/советы или другие мысли по всей проблеме дизайна и поместить их в перспективу. Я чувствую себя немного потерянным там.
Ответы
Ответ 1
Я использую каналы для связи между компонентами, которые не могут общаться через курсоры.
Например, я использую каналы, когда:
- Коммуникационные компоненты не разделяют состояние приложения (например, их курсоры указывают на разные ветки иерархической структуры данных).
- изменения, передаваемые в реальном времени вне состояния приложения (например, компонент A хочет изменить локальное состояние компонента B, а компонент B не является дочерним элементом A (иначе это можно сделать, передав
:state
в om/build
)
- Я хочу общаться с чем-то вне дерева компонентов Om
Обратите внимание, что мне нравится сохранять "состояние домена" в атоме состояния приложения и состоянии GUI в локальном состоянии компонента. То есть состояние приложения - это то, что отображается, а - это состояние. (где "как" также относится к какой части) Например, если вы пишете текстовый редактор, состояние приложения - это редактируемый документ, а локальное состояние - это какая страница редактируется, независимо от того, выбран ли полужирный шрифт.
В общем, я использую один канал связи, на который я помещаю пары [topic value]
. Затем я использую pub и sub для маршрутизации сообщений. Например, (def p (async/pub ch first))
использовать тему для отправки событий и (om/sub p my-ch :foo)
для получения сообщений с темой :foo
до my-ch
. Обычно я сохраняю этот единственный канал связи в общем состоянии Om.
Иногда я буду использовать несколько каналов, но я бы сделал это, чтобы настроить конкретные конвейеры или рабочие процессы, а не для обмена сообщениями общего назначения. Например, если у меня есть конвейер обработки компонентов, делающих материал для потока данных, тогда я мог бы установить это как цепочку каналов с конечными точками, подключенными к моему приложению Om. Для общего развития пользовательского интерфейса это редко.
Я также играю с системой сигналов/слотов Qt-esque для своих компонентов Om, и я все еще экспериментирую с использованием общих каналов сигналов против того, чтобы каждый сигнал был его собственным каналом. Я еще не определился, какой подход лучше.