Firebase, Redux, Observables.

Alpha Shuro
AndroidPub
Published in
2 min readApr 10, 2017
Interactive marble diagram from http://rxmarbles.com

When I first learned about observables I was sceptical about what value I would get from them. Many of the operations they provide are already available with `Array#functions` and ES6 `Promises`.

What could possibly be the benefit of adding this entire library and adding the extra cognitive load to do something I can already do with modern JavaScript? — Me, evaluating Observables

I usually use React when I write Single Page Apps, and add Redux when I need some sane state management. This works well when you have simple functions that make backend calls and update state when the result is received, however firebase uses WebSockets to give you realtime updates as your data changes. In order to use this functionality, you need to essentially subscribe to all the changes to data and update your state accordingly.

In order to avoid polluting my entire project with firebase imports to make it easier to test the application, to be able to change the event source from firebase to anything else, and to separate concerns to make it easier to implement features, I wanted to export an API that abstracts firebase away and exposes only the events that the app needs to know about (i.e. user has authenticated, data has arrived, new data has been added, etc) I had to export an API that allows listening for many asynchronous events over time. This is what Observables have been selling, so I decided to give them a chance.

The experience was great, the use of observables allowed me to implement both the API and the react components with much simpler functional code, gaining among other things:

  • the ability to cancel incomplete http requests (to avoid computations that happen when invalid requests complete, e.g. that evil “setState on unmounted component” error)
  • the ability to unsubscribe from events when components are unmounted
  • automatic cleanup of resources with `Observable.using`
  • the ability to use other observables to subscribe to related events e.g. subscribing to profile events for the currently logged in user
const dbRef = path => firebase.database().ref(path);
const observeOn = event => obj => Observable.fromEvent(obj, event);
const setRef = data => ref => ref.set(data);
const getVal = snapshot => snapshot.val();
/**
* Emits a `user` object when a user signs in
* Emits null when a user signs out
*/
export const authChanged = Observable.using(firebase.auth, auth =>
Observable.create(observer =>
auth.onAuthStateChanged(user => observer.next(user)));
export const profileRefSource = authChanged
.filter(Boolean) // ignore logged out users
.pluck('uid')
.map(concat('users/'))
.map(dbRef);
export function getProfile() {
return profileRefSource
.flatMap(observeOn('value'))
.map(getVal);
}
// bonus function for updating the user's profile using the same observable
export function updateProfile(profile) {
return profileRefSource
.map(setRef(profile));
}

If you too are on the path of the Observables, I encourage you to continue learning them, you will find that they will easily present themselves as the solution to many async event-based problems.

--

--

Alpha Shuro
AndroidPub

Most of my life is spent on practical philosophy, coding, gaming, and living.