Auth Effects and Firebase Initialization
We dispatched an event and wrote a handler. The handler returned an effects map, with a custom effect `:firebase/email-auth`. In this chapter, we'll create the custom effect handler and initialize the Firebase app.
Auth effects and Firebase initialization#
We dispatched an event and wrote a handler. The handler returned an effects map, with a custom effect :firebase/email-auth
.
In this chapter, we'll create the custom effect handler and initialize the Firebase app.
Create the effect handler#
Effect handlers are impure functions that can be used to perform side-effects like calling APIs, saving data to local storage, sending an email etc. In our case, the side-effect will log the user into Firebase and cache user details in app-db
. The function re-frame.core/reg-fx
can be used to register custom effects.
In smaller applications, you might have a namespace app.effects
for all the effects. In our case, we are going to place this function in app.domain.firebase
, since the effect is related to Firebase.
reg-fx
accepts two arguments: an effect id and a handler function. Reframe calls the handler function with arguments passed to effect map.
(rf/reg-fx
:firebase/email-auth
(fn [{:keys [email password]}]
(-> firebase
(.auth)
(.signInWithEmailAndPassword email password)
(.catch (fn [err]
(rf/dispatch [::email-auth-error err]))))))
To keep things in context, here is the event handler (built in the last chapter) that requested execution of this effect:
(rf/reg-event-fx
::login-with-email ;; equivalent to :app.domain.firebase/login-with-email
(fn [cofx [_ form-state]]
{:db (assoc (:db cofx)
::login-loading? true)
:firebase/email-auth form-state}))
The event returned an effect map requesting to execute effect
:firebase/email-auth
with argumentform-state
, which is a map with keys:email
and:password
The registered effect
:firebase/email-auth
's handler function is called with this map, which we destructure as{:keys [email password]}
The effect interacts with the Firebase SDK and calls the impure function
signInWithEmailAndPassword
. Notice the use of->
- the thread-first macro. The JS equivalent of the function call above is:
firebase.auth()
.signInWithEmailAndPassword(email, password)
.catch(function(err) {})
;
The sign-in function is impure because a remote resource is called
We also handle the error case and
dispatch
the::email-auth-error
event, which is again impure. We have not created a handler for::email-auth-error
yet
You might be wondering where the login success case is. Good observation! Firebase Auth expects us to register an "auth state observer" globally. Firebase also expects us to initialize a Firebase app globally.
Create Firebase auth state observer#
This observer function is called each time the auth state changes, ie when a user logs in or out. We will hook this observer in Reframe by dispatching events when the auth state changes. In real-world apps, this use case is similar to listening to sockets. A global listener waits for messages and dispatch
es Reframe events as messages are received.
Since this functionality is related to Firebase, we'll define the observer in the app.domain.firebase
namespace:
(defn firebase-user->user