Fix bug which meant that post-event-callbacks were not called for dispatch-sync

This commit is contained in:
Mike Thompson 2016-06-04 00:13:41 +10:00
parent 9adf4cf40b
commit 5a214fc83b
2 changed files with 33 additions and 30 deletions

View File

@ -50,6 +50,7 @@ Improvements
- XXXX middleware for spec checking of event vectors - XXXX middleware for spec checking of event vectors
- XXXX better subscriptions of subscriptions - XXXX better subscriptions of subscriptions
- XXX spec definitions of what subscriptions deliver ?? - XXX spec definitions of what subscriptions deliver ??
- Bug fix: `post-event-callbacks` were not called when `dispatch-sync` was called.
- added new API `re-frame.core/remove-post-event-callback`. See doc string. - added new API `re-frame.core/remove-post-event-callback`. See doc string.
- when an event-handler makes no change to `app-db`, the `debug` middleware now logs a - when an event-handler makes no change to `app-db`, the `debug` middleware now logs a
single line saying so, rather than a "group". Makes it slightly easier to grok single line saying so, rather than a "group". Makes it slightly easier to grok

View File

@ -69,8 +69,8 @@
;; Abstract representation of the Queue ;; Abstract representation of the Queue
(defprotocol IEventQueue (defprotocol IEventQueue
;; -- Public API ;; -- API
(enqueue [this event]) (push [this event])
(add-post-event-callback [this f]) (add-post-event-callback [this f])
(remove-post-event-callback [this f]) (remove-post-event-callback [this f])
@ -79,12 +79,13 @@
;; -- Finite State Machine actions ;; -- Finite State Machine actions
(-add-event [this event]) (-add-event [this event])
(-process-1st-event [this]) (-process-1st-event-in-queue [this])
(-run-next-tick [this]) (-run-next-tick [this])
(-run-queue [this]) (-run-queue [this])
(-exception [this ex]) (-exception [this ex])
(-pause [this later-fn]) (-pause [this later-fn])
(-resume [this])) (-resume [this])
(-call-post-event-callbacks[this event]))
;; Concrete implementation of IEventQueue ;; Concrete implementation of IEventQueue
@ -95,18 +96,15 @@
;; -- API ------------------------------------------------------------------ ;; -- API ------------------------------------------------------------------
(enqueue [this event] (push [this event] ;; presumably called by dispatch
;; put an event into the queue (presumably because of a dispatch)
(-fsm-trigger this :add-event event)) (-fsm-trigger this :add-event event))
(add-post-event-callback [this f] (add-post-event-callback [_ callback-fn]
;; register a callback to be invoked after events are processed ;; register a callback function to be called after each event is processed
;; Useful to so-called isomorphic, server-side rendering frameworks (set! post-event-callback-fns (conj post-event-callback-fns callback-fn)))
;; or when you want to do specialised event processing.
(set! post-event-callback-fns (conj post-event-callback-fns f)))
(remove-post-event-callback [this f] (remove-post-event-callback [_ callback-fn]
(set! post-event-callback-fns (remove #(= % f) post-event-callback-fns))) (set! post-event-callback-fns (remove #(= % callback-fn) post-event-callback-fns)))
;; -- FSM Implementation --------------------------------------------------- ;; -- FSM Implementation ---------------------------------------------------
@ -114,9 +112,9 @@
(-fsm-trigger (-fsm-trigger
[this trigger arg] [this trigger arg]
;; The following "case" imoplements the Finite State Machine. ;; The following "case" impliments the Finite State Machine.
;; Given a "trigger", and the existing FSM state, it computes the new ;; Given a "trigger", and the existing FSM state, it computes the
;; FSM state and the tranistion action (function) to perform. ;; new FSM state and the tranistion action (function).
(let [[new-fsm-state action-fn] (let [[new-fsm-state action-fn]
(case [fsm-state trigger] (case [fsm-state trigger]
@ -147,26 +145,23 @@
[:paused :add-event] [:paused #(-add-event this arg)] [:paused :add-event] [:paused #(-add-event this arg)]
[:paused :resume ] [:running #(-resume this)] [:paused :resume ] [:running #(-resume this)]
(throw (str "re-frame: state transition not found. " fsm-state " " trigger)))] (throw (js/Error. (str "re-frame: router state transition not found. " fsm-state " " trigger))))]
;; The "case" above computed both the new FSM state, and the action. Now, make it happen. ;; The "case" above computed both the new FSM state, and the action. Now, make it happen.
(set! fsm-state new-fsm-state) (set! fsm-state new-fsm-state)
(when action-fn (action-fn)))) (when action-fn (action-fn))))
(-add-event (-add-event
[this event] [_ event]
(set! queue (conj queue event))) (set! queue (conj queue event)))
(-process-1st-event (-process-1st-event-in-queue
[this] [this]
(let [event-v (peek queue)] (let [event-v (peek queue)]
(try (try
(handle event-v) (handle event-v)
(set! queue (pop queue)) (set! queue (pop queue))
(-call-post-event-callbacks this event-v)
;; Tell all registed callbacks that an event was just processed.
;; Pass in the event just handled and the new state of the queue
(doseq [f post-event-callback-fns] (f event-v queue))
(catch :default ex (catch :default ex
(-fsm-trigger this :exception ex))))) (-fsm-trigger this :exception ex)))))
@ -183,7 +178,7 @@
(-fsm-trigger this :finish-run nil) (-fsm-trigger this :finish-run nil)
(if-let [later-fn (some later-fns (-> queue peek meta keys))] ;; any metadata which causes pausing? (if-let [later-fn (some later-fns (-> queue peek meta keys))] ;; any metadata which causes pausing?
(-fsm-trigger this :pause later-fn) (-fsm-trigger this :pause later-fn)
(do (-process-1st-event this) (do (-process-1st-event-in-queue this)
(recur (dec n))))))) (recur (dec n)))))))
(-exception (-exception
@ -195,9 +190,15 @@
[this later-fn] [this later-fn]
(later-fn #(-fsm-trigger this :resume nil))) (later-fn #(-fsm-trigger this :resume nil)))
(-call-post-event-callbacks
[_ event-v]
;; Call each registed post-event callback.
(doseq [callback post-event-callback-fns]
(callback event-v queue)))
(-resume (-resume
[this] [this]
(-process-1st-event this) ;; do the event which paused processing (-process-1st-event-in-queue this) ;; do the event which paused processing
(-run-queue this))) ;; do the rest of the queued events (-run-queue this))) ;; do the rest of the queued events
@ -220,19 +221,20 @@
(dispatch [:delete-item 42])" (dispatch [:delete-item 42])"
[event-v] [event-v]
(if (nil? event-v) (if (nil? event-v)
(error "re-frame: \"dispatch\" is ignoring a nil event.") (throw (js/Error. "re-frame: you called \"dispatch\" without an event vector."))
(enqueue event-queue event-v)) (push event-queue event-v))
nil) ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False nil) ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False
(defn dispatch-sync (defn dispatch-sync
"Immediately process an event using the registered handler. "Immediately process an event using the registered handler.
Generally, don't use this. Use \"dispatch\" instead. It Generally, you shouldn't use this. Use \"dispatch\" instead. It
is an error to even try and use it within an event handler. is an error to even try and use it within an event handler.
Usage example: Usage example:
(dispatch-sync [:delete-item 42])" (dispatch-sync [:delete-item 42])"
[event-v] [event-v]
(handle event-v) (handle event-v)
nil) ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False (-call-post-event-callbacks event-queue event-v) ;; ugly hack. Just so post-event-callbacks get called
nil) ;; Ensure nil return. See https://github.com/Day8/re-frame/wiki/Beware-Returning-False