Async event system for Clojure - re-frame patterns for JVM.
hive-events brings re-frame's elegant event-driven architecture to Clojure/JVM with first-class async support via core.async. It provides:
:db, :dispatch, custom)core.async channelsAdd to your deps.edn:
{:deps {io.github.BuddhiLW/hive-events {:git/tag "v0.1.0" :git/sha "..."}}}
(require '[hive.events :as ev])
;; Initialize with your app state atom
(ev/init! (atom {:count 0}))
;; Register a simple event handler
(ev/reg-event-db :counter/inc
(fn [db [_ amount]]
(update db :count + (or amount 1))))
;; Dispatch events
(ev/dispatch [:counter/inc 5])
(ev/dispatch-sync [:counter/inc 1]) ; synchronous
Two types of handlers are supported:
For handlers that only update the database:
(ev/reg-event-db :user/set-name
(fn [db [_ name]]
(assoc db :user-name name)))
For handlers that produce multiple effects:
(ev/reg-event-fx :user/fetch
(fn [{:keys [db]} [_ user-id]]
{:db (assoc db :loading? true)
:http {:url (str "/api/users/" user-id)
:on-success :user/fetch-success}}))
Register custom effect handlers:
(ev/reg-fx :http
(fn [{:keys [url method on-success]}]
;; perform HTTP request
;; dispatch on-success event with response
))
(ev/reg-fx :local-storage
(fn [{:keys [key value]}]
(.setItem js/localStorage key value)))
Built-in effects:
:db - Update application state:dispatch - Dispatch another event:dispatch-n - Dispatch multiple events:dispatch-later - Dispatch after delayInject dependencies into handlers:
(ev/reg-cofx :now
(fn [coeffects]
(assoc coeffects :now (System/currentTimeMillis))))
(ev/reg-event-fx :log/timestamp
[(ev/inject-cofx :now)]
(fn [{:keys [db now]} _]
{:db (assoc db :last-timestamp now)}))
Built-in coeffects:
:now - Current timestamp:random - Random number:uuid - Random UUID stringCompose cross-cutting concerns:
(def validate-user
(ev/->interceptor
:id :validate-user
:before (fn [ctx]
(let [user (get-in ctx [:coeffects :db :user])]
(if (valid? user)
ctx
(assoc ctx :effects {:dispatch [:error/invalid-user]}))))))
(ev/reg-event-fx :user/update
[validate-user ev/debug]
(fn [{:keys [db]} [_ changes]]
{:db (update db :user merge changes)}))
Built-in interceptors:
debug - Log event and effectstrim-v - Remove event id from vectorpath - Focus handler on db path(require '[hive.events.async :as async])
;; Dispatch with timeout
(async/dispatch-with-timeout [:slow/operation] 5000)
;; Retry with exponential backoff
(async/dispatch-with-retry [:flaky/api-call]
{:max-retries 3
:initial-delay-ms 100
:retry-pred (fn [ctx] (get-in ctx [:effects :error]))})
;; Debounced dispatch (search-as-you-type)
(async/dispatch-debounced :search [:search/query "foo"] 300)
;; Throttled dispatch (scroll handler)
(async/dispatch-throttled :scroll [:ui/position pos] 100)
;; Pub/sub event streams
(let [ch (async/subscribe-events :user/login)]
(go-loop []
(when-let [event (<! ch)]
(println "Login:" event)
(recur))))
;; Sagas for complex workflows
(async/saga [:order/created :payment/completed]
(fn [event state]
(case (first event)
:order/created
{:state (assoc state :order (second event))
:dispatch [:payment/initiate (:id (second event))]}
:payment/completed
{:state (assoc state :paid? true)
:dispatch [:fulfillment/start (:order-id state)]})))
hive.events (facade)
├── hive.events.interceptor ; Interceptor chain
├── hive.events.fx ; Effects registry
├── hive.events.cofx ; Coeffects registry
├── hive.events.router ; Event dispatch
└── hive.events.async ; Async patterns (JVM)
[:event-id & args]core.async for JVMMIT
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |