Citrus event handling is implemented via a handler function that processes
a batch of events. The behavior of this handler function can be customized
by passing an alternative handler function as :citrus/handler
when creating
a reconciler instance.
By providing a custom :citrus/handler
you can adapt your event handling
in ways that haven't been anticipated by the Citrus framework.
Initially this customization option has been motivated by the need to access all controllers state in event handlers.
:bulb: This feature is experimental and subject to change. Please report your experiences using them in this GitHub issue.
When constructing a reconciler the :citrus/handler
option can be used to
pass a custom handler that processes a batch of events.
:citrus/handler
should be a function like
(fn handler [reconciler events])
;; where `events` is a list of event tuples like this one
[[ctrl-key event-key event-args] ; event 1
[ctrl-key event-key event-args]] ; event 2
When not passing in anything for this option, the handler will default to
citrus.reconciler/citrus-default-handler
, which behaves identical to the
regular event handling of Citrus as of v3.2.3
.
The handler will process all events of the current batch before
resetting the reconciler state
. This reduces the number of watch triggers
for subscriptions and similar tools using add-watch
with the reconciler
state
atom.
With the ability to override the citrus/handler
the controller
and
effect-handlers
options almost become superfluous as all behavior influenced
by these options can now also be controlled via :citrus/handler
. Some ideas
for things that are now possible to build on top of Citrus that previously
weren't:
Note that breaking out of controllers as Citrus provides them impacts how Citrus'
broadcast
functions work.broadcast!
andbroadcast-sync!
rely on what is being passed to the reconciler as:controllers
.
:wave: Have you used :citrus/handler
to do something interesting? Open a PR and share your approach here!
Event handlers currently take four arguments [controller-kw event-kw event-args co-effects]
. As described above one motivation for custom handlers
has been to give event handlers access to the entire state of the application.
By implementing a new handler based on citrus.reconciler/citrus-default-handler
we can change how our controller multimethods are called, replacing the co-effects
argument with the full state of the reconciler.
Co-effects are largely undocumented right now and might be removed in a future release. Please add a note to this issue if you are using them.
:point_right: Here's a commit that adapts Citrus' default handler to pass the reconciler's full state as the fourth argument. Part of the diff is replicated below:
diff --git a/src/citrus/reconciler.cljs b/src/citrus/reconciler.cljs
index f8de8c5..5a95a77 100644
--- a/src/citrus/reconciler.cljs
+++ b/src/citrus/reconciler.cljs
@@ -14,17 +14,15 @@
(release-fn id))
(vreset! scheduled? (schedule-fn f)))
-(defn citrus-default-handler
- "Implements Citrus' default event handling (as of 3.2.3).
-
- This function can be copied into your project and adapted to your needs.
+(defn adapted-default-handler
+ "An adapted event handler for Citrus that passes the entire reconciler
+ state as fourth argument to controller methods.
`events` is expected to be a list of events (tuples):
[ctrl event-key event-args]"
[reconciler events]
(let [controllers (.-controllers reconciler)
- co-effects (.-co_effects reconciler)
effect-handlers (.-effect_handlers reconciler)
state-atom (.-state reconciler)]
(reset!
@@ -36,13 +34,7 @@
(do
(assert (contains? controllers ctrl) (str "Controller " ctrl " is not found"))
(let [ctrl-fn (get controllers ctrl)
- cofx (get-in (.-meta ctrl) [:citrus event-key :cofx])
- cofx (reduce
- (fn [cofx [k & args]]
- (assoc cofx k (apply (co-effects k) args)))
- {}
- cofx)
- effects (ctrl-fn event-key event-args (get state ctrl) cofx)]
+ effects (ctrl-fn event-key event-args (get state ctrl) state)]
(m/doseq [effect (dissoc effects :state)]
(let [[eff-type effect] effect]
(when (s/check-asserts?)
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close