Timeout Effect in Re-frame
Sometimes you need to delay an Event a certain amount of time. Let's say
you want an alert to appear for twenty seconds before disappearing. We
can store the alert message in the Database, but how do we make it
disappear after the right time? We could set a timeout, using
setTimeout()
, but Event handlers should be pure to make them more
testable. We need to turn setting a timeout into an Effect.
Let's make the shell of an Effect:
(rf/reg-fx
:timeout
(fn [{}]
))
We can pass in a time and an Event to dispatch. We then call
setTimeout()
.
(rf/reg-fx
:timeout
(fn [{:keys [event time]}]
(js/setTimeout
(fn []
(rf/dispatch event))
time)))
That's great! Another feature of the JavaScript timeouts is the ability
to cancel them with clearTimeout()
. setTimeout()
will return an id,
which we later pass to clearTimeout()
.
We cancel timeouts if we store the id somewhere. Let's make a new atom to store these ids.
(defonce timeouts (reagent/atom {}))
We can use our own id when we create the Event so we can refer to it later:
(rf/reg-fx
:timeout
(fn [{:keys [id event time]}]
If we already have a timeout for this id, let's cancel it:
(rf/reg-fx
:timeout
(fn [{:keys [id event time]}]
(when-some [existing (get @timeouts id)]
(js/clearTimeout existing))
Then, we dissoc
it from the timeouts
atom.
(rf/reg-fx
:timeout
(fn [{:keys [id event time]}]
(when-some [existing (get @timeouts id)]
(js/clearTimeout existing)
(swap! timeouts dissoc id))
(when (some? event)
(swap! timeouts assoc id
(js/setTimeout
(fn []
(rf/dispatch event))
time)))))
There! Now we can use it like the following. We can set the alert message and trigger its removal after 20 seconds.
(rf/reg-event-fx
:set-alert
(fn [cfx [_ msg]]
{:db (assoc (:db cfx) :alert-message msg)
:timeout {:id :alert-message
:event [:remove-alert]
:time 20000}}))
(rf/reg-event-db
:remove-alert
(fn [db]
(dissoc db :alert-message)))
;; ...
(rf/dispatch [:alert-message "Please have a nice day!!"])
Try it out!
More posts in this Re-frame Series
- State in Re-frame
- The Re-frame Building Blocks Guide
- Guide to Reagent
- React Lifecycle for Re-frame
- Database Structure in Re-frame
- Re-frame, a Visual Explanation
- Optimistic Update in Re-frame
- Timeout Effect in Re-frame ← you are here
- Why Re-frame instead of Om Next
- 6 things Reacters do that Re-framers avoid