Auth Subscriptions
In this chapter, we'll connect the UI to the Reframe loop and create loading indicators and subscriptions to check if the user logged in successfully.
Auth subscriptions and container components#
We dispatched an event, created an event handler, executed the login side-effect, and handled errors. All these actions caused the app-db
to change. Next, we need to update our UI to reflect changes made to app-db
.
Subscriptions#
Reframe subscriptions are reactive views on top of the app-db
. Fancy terms, but a simple idea. A subscription lets you watch a subset of app-db
, and cause any subscribed component to re-render when the watched set changes.
Login loading subscription#
A visual indicator for long-running tasks is good UX practice. We added a :a.d.f/login-loading?
flag and can show a visual indicator by subscribing to this state.
:a.d.f
is short for :app.domain.firebase
namespace.
A subscription can be created using the re-frame.core/reg-sub
method. This function accepts a subscription id and a handler function. This handler function is called with the app-db
as the first argument and the subscription vector as the second argument.
To show a login indicator, we need two logical pieces:
a registered subscription that pulls out the loading flag from
app-db
a subscribed component that listens to this subscription
Let's register the subscription. The code for this will go in the app.domain.firebase
namespace. An alternate convention is to have an app.subs
namespace to handle all subscriptions. We'll stick to our domain-based strategy, but feel free to experiment:
(rf/reg-sub
::login-loading?
(fn [db _]
(-> db ::login-loading?)))
After registration, any component can subscribe to this subscription.
Login loading subscriber#
The component rendered at /login
needs this information to show a loading indicator. Blueprint's Button
component accepts a prop :loading
, which when set to true
, disables the button and shows a spinner animation.
The reframe.core/subscribe
method lets us hook a component to a subscription. It returns an atom
. Let's update the app.pages.login/page
component to be subscribed. Add the subscription to the let
binding, just next to email
and password
:
login-loading? @(rf/subscribe [:app.domain.firebase/login-loading?])
This subscription didn't require any arguments, but arguments can be passed as additional elements to the vector supplied to rf/subscribe
and can be captured in the handler (rf/subscribe :sub-id (fn [sub-id arg1 arg2]))
. The second argument, that we ignored using an _
underscore in the subscription above, will be this vector - similar to event handlers.
The last step is to pass login-loading?
as a prop to the Button
component:
[:> Button {:text "Login" :icon "log-in" :intent (.-PRIMARY Intent)
:class "mt-4 mb-2" :loading login-loading?
:onClick #(rf/dispatch [:app.domain.firebase/login-with-email @state])
This page is a preview of Tinycanva: Clojure for React Developers