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.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Tinycanva: Clojure for React Developers course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Tinycanva: Clojure for React Developers, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Tinycanva: Clojure for React Developers
  • [00:00 - 00:09] We discussed an event and wrote a handler in the previous chapter. The handler returned an effects map with a custom effect Firebase email all.

    [00:10 - 00:25] In this chapter, we will create the custom effect and initialize the Firebase application. 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.

    [00:26 - 00:36] In our case, the side effect will log the user in to Firebase and cache user details in RDB. The function "RegisterFX" can be used to register custom effects.

    [00:37 - 00:50] In smaller applications, you might have a namespace like "app.effects" for all the effects. In our case, we are going to place this function in the "app.domain.firebase" namespace since the effect is related to Firebase.

    [00:51 - 01:00] Firebase's behavior effects accepts two arguments, an effect ID and a handler function. The frame calls the handler function with arguments passed to the effect map.

    [01:01 - 01:10] Let's define the Firebase email auth handler. To keep things in context, here's the event handler that we built in the last chapter that requested the execution of this effect.

    [01:11 - 01:25] The event returned an effect map requesting to execute Firebase email auth with argument form state, which is a map with keys, email and password. The registered effect Firebase email auth, these structures the email and password.

    [01:26 - 01:35] The effect then interacts with Firebase SDK and calls the impure function "sign in" with email and password. Notice the use of threadfirst macro.

    [01:36 - 01:42] This is the JS equivalent of the effect handler function. The sign in function is impure because the remote resource is called.

    [01:43 - 01:52] We also handle the error case and dispatch the email auth error event, which again is impure. I'm not created a handler for email auth error yet.

    [01:53 - 01:59] You might be wondering where is the login success case. Firebase expects us to register an auth state observer globally.

    [02:00 - 02:05] We also need to initialize the Firebase app globally. Let's create this observer.

    [02:06 - 02:17] The observer function is called each time the auth state changes, i.e. a user logs in or out. We will hook this observer in reframe by dispatching events when the auth state changes.

    [02:18 - 02:28] In real world apps, this use case is similar to listening to sockets. A global listener waits for messages and dispatches three frame events as messages are received.

    [02:29 - 02:39] Since the functionality is related to Firebase, we will define the observer in app domain.firebase namespace. We created a function observe auth state with defn-suffix.

    [02:40 - 02:45] The hyphen signifies a private function. That is this function can only be called in the current namespace.

    [02:46 - 02:54] The function internally calls or auth state changed on Firebase auth object. The callback function is passed as the first argument.

    [02:55 - 03:11] The callback receives a user object, which is a JavaScript object returned by Firebase when a user logs in or nil when the user logs out. Depending on the existence of user, we dispatch the user logged in or user logged out events which we haven't registered yet.

    [03:12 - 03:21] The function Firebase user to user converts the JS object into a closure map. Let's create the login success, error and logout handlers.

    [03:22 - 03:34] The event handlers of the login and logout dispatch will add or remove this user from app DB. The login error handler will set the error message in app DB and unset the loading indicator.

    [03:35 - 03:50] REG event DB is similar in scope to REG event FX, except it receives only the DB co-effect and returns the new value of DB. Unlike REG event FX, that receives all co-effects and return an effects map.

    [03:51 - 03:58] Since most frontend events only change the app DB, the frame provides us with this shorthand. These two calls are identical.

    [03:59 - 04:11] For any Firebase function to work, we need to initialize a Firebase app using client configuration. Just that you might need other configurations in a real world app like REST API and Points analytics IDs.

    [04:12 - 04:27] Also, you might have different set of configurations for different environments . Our configuration strategy is to have an app.config namespace with top-level defines for each environment and a for ENV function to select the applicable configuration.

    [04:28 - 04:31] Let's create this namespace. The credentials will be different for you.

    [04:32 - 04:40] Make sure that you add your own credentials as these might not work. We can skip adding credentials for other environments for a later chapter.

    [04:41 - 04:53] With this strategy, we need to ensure that the shape of all config maps is the same. The for ENV function takes an environment key and returns the respective configuration for that environment.

    [04:54 - 05:03] Firebase SDK allows us to initialize multiple applications using the initialize app function. It also returns a list of initialized apps via the Firebase apps property.

    [05:04 - 05:13] Our strategy is to initialize Firebase once when the app is rendered. We will define an init method in the app to main.pybase and call it in the boot strap process in app.core.

    [05:14 - 05:21] The config argument is the value of Firebase map defined in app.config. The zero function is same as equal to x0.

    [05:22 - 05:34] Firebase apps returns a JavaScript list of initialized apps. JLENTH is like length function, but it operates on JavaScript arrays, unlike length which needs a CLJS sequence.

    [05:35 - 05:46] We convert config to a JS map because Firebase initialize app is a JS function and we also start observing the odd state. Let's import the configuration and initialize Firebase application.

    [05:47 - 05:56] We need this configuration in app.core to initialize Firebase app. We can do this by importing app.config namespace and calling for ENV method.

    [05:57 - 06:05] Here we define the depth config as the applicable config. In later chapters we will load this configuration depending on an environmental variable.

    [06:06 - 06:11] Our app.core/main is the entry point of the application. Currently it calls the render function.

    [06:12 - 06:18] Firebase 2 needs to be initialized just once. When the app loads, hence we can call the init function here just before render .

    [06:19 - 06:31] We also need to require the Firebase domain in app.core function using require app.domain interface. We pass the Firebase configuration from applicable config to the init function.

    [06:32 - 06:39] The tutorial is guided and you won't see any errors or issues because we have already fixed the issues. But in real life this won't be the case.

    [06:40 - 06:46] You will have to debug your application and figure out why you are apped in render. There are many ways to go about this.

    [06:47 - 06:55] We recommend using the notes in the chapters to get the details. The last piece is to add subscriptions and complete the loop.

    [06:56 - 07:02] will do that in the next chapter.