How to Create Firebase Data Subscriptions in Reframe
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.
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.
Get unlimited access to Tinycanva: Clojure for React Developers, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:09] We dispatched an event, created an event handle, executed the login side effect and hand layers. All these actions caused the appdb to change.
[00:10 - 00:19] Next, we need to update our UI to reflect the changes made to the appdb. The frame subscriptions are reactive views on top of appdb.
[00:20 - 00:31] Fancy terms but simple idea. A subscription lets you watch a subset of the appdb and causes any subscribed component to re-linder when the watch set of keys change.
[00:32 - 00:41] A visual indicator for long-running tasks is a good UX practice. We added a login loading flag and can show a visual indicator by subscribing to it.
[00:42 - 00:52] ADF is short for app domain via base namespace. A subscription can be created using the reframe code / register sub-method.
[00:53 - 01:03] This function accepts a subscription ID and a handler function. The handler function is called with the appdb as the first argument and the subscription vector as the second argument.
[01:04 - 01:16] To show a login indicator, we need two logical pieces. A registered subscription that pulls out the login loading flag from appdb and a subscribed component that listens to this subscription.
[01:17 - 01:22] Let's register the subscription. The code for this will go to app domain.firebase namespace.
[01:23 - 01:33] An alternate convention is to have a top-level app.subs namespace to handle all subscriptions. We will stick to our domain strategy but feel free to experiment.
[01:34 - 01:45] The suggested sub-component takes the db and returns the login loading flag. After registration, any component can subscribe to this subscription.
[01:46 - 02:00] The component render at /login needs this information to show a loading indicator. Blueprints button component accepts sub-prob loading which when set to true, disables the button and shows a spinner animation.
[02:01 - 02:11] The reframe.co/subscribe method lets us hook a component to a subscription. It returns an atom that can be de-referenced to get the state of the db.
[02:12 - 02:31] Let's update the app.pages login page and add the subscription to let binding just next to the email and password state. This subscription did not require any arguments but arguments can be passed as additional elements to vector and can be captured as an argument to subscription handler.
[02:32 - 02:38] It is similar to event handlers. The last step is to pass login loading as a prop to the button component.
[02:39 - 02:54] We also suggest adding a print colon colon login loading statement to the top of your component while you are testing this manually. So you can get a log statement in your console. Let's test the system. We have finished the loop.
[02:55 - 03:03] If you now click the button on the login page, the data in the input field will be sent to Firebase. And you should at least see a login indicator.
[03:04 - 03:12] Click the button to see if things work. You can also check the console because the request might execute too fast and the UI might not re-render with the indicator.
[03:13 - 03:28] In the last chapter, we configured Firebase email auth effect to catch and dispatch email auth error event in case of errors. The handler for this event pulls out the message property from the error object and saves it in app table.
[03:29 - 03:33] But this error should be visible to the user. Let's create a subscription in app domain Firebase.
[03:34 - 03:46] This time we use the shorthand syntax for inline function. Percentage 1 denotes the first argument. Note that the subscription ID and the app TBK is same for both our subscriptions.
[03:47 - 03:50] This is just a coincidence. The subscription ID can be anything.
[03:51 - 04:00] We need the app.pages.login page to subscribe to this subscription as well. This subscription should be inside the let binding similar to the other one.
[04:01 - 04:08] Finally, we need to show the error message to the user. Blueprint's callout component is ideal for our use case.
[04:09 - 04:14] We can add the error just below the button component. The login error is a string message.
[04:15 - 04:21] You can inspect JavaScript objects using js/consoul.log. This will print your object to your console.
[04:22 - 04:28] And we show a callout component only when a login error is present. If you click the login button now, you should see an error.
[04:29 - 04:38] The refresh dashboard lists the events that occurred and the progression of app TB over time. It took us three chapters to build a system.
[04:39 - 04:46] In terms of the mental model, we took the following steps. The user fills the form and the state is saved in a local random.
[04:47 - 04:57] The user clicks the login button and the reframe event is dispatched. The event handler for login event runs and sets the login loading flag to true.
[04:58 - 05:08] The handler also requests to run the custom Firebase auth effect. A subscriber is subscribed to login loading and re-renders the UI with the loading spinner.
[05:09 - 05:19] In case of errors, the loading flag is set to false and the error is set in app TB. A subscriber reads this error message and re-renders the UI with this message.
[05:20 - 05:31] If the login is successful, then the user is set in app TB and the login loading flag is set to false. When a user authenticates successfully, the user is cached in app TB.
[05:32 - 05:45] This happens because observe auth state function dispatches user logged in event which sets the user in app TB. We'll refer to the logged in user as me. Let's create a subscription to listen to me.
[05:46 - 05:55] But this is not enough. There are more cases to handle with the logged in user. If a user successfully logs in, we need to redirect them to a private route.
[05:56 - 06:17] If the user logged in and she visits login again, we need to redirect them to the private route automatically. And if a user is not logged in and tries to access a private route, we need to redirect them to the login page. You're going to handle these cases by creating two wrapper components, auth private and auth public.
[06:18 - 06:28] Public routes like login and register will be wrapped in auth public component. Auth public will subscribe to me. If me is not nil, the component will redirect to a protected route.
[06:29 - 06:34] All private routes will be wrapped in auth private component. This component will subscribe to the logged in user.
[06:35 - 06:45] And if at any point of time, the user in app TB becomes nil, the user will be redirected to the home page. We will build these components in the next chapter.