Create your own Redux with RxJS
Reactivity.
Reactive programming is something you might have heard of, but might not know how to approach yet. In very simple words, it's a programming paradigm like 'Functional programming' or 'Object-oriented programming' which focuses on a different aspect, namely, how to write programs that automatically do something when something else happens.
Event handlers in JS are naturally reactive and demonstrate this well:
They listen for events and automatically trigger a handler (in this case handleClick
) when the event happens, which in turn does something (in this case, some fancy stuff).
In fact events are a nice way to model things that are yet to happen or finish (like asynchronous code returning a value).
A Note on Sequences:
An array is the simplest kind of collection of data. It is a sequence of things; which is as simple as a collection can get.
Arrays provide ways to deal with collections easily. You are probably familiar with loops that let you process an array by iterating over its elements.
Also, many languages like JavaScript, provide higher order functions like map
and filter
, that let you pass a function that will be applied to each element in the array.
Adding 2 to an array of numbers is easy with Array.prototype.map
Array.prototype.map
returns a new array and does not mutate the old one. Moreover, the array prototype methods can be chained.
These two facts let us deal with arrays in a clean, declarative and functional way.
Wouldn't it be great if we had a way to deal with events and asynchronous operations in a clean and familiar way, much similar to the one mentioned above?
Well, this is exactly what ReactiveX does. ReactiveX is a language independent specification that describes an API (functions and interfaces) that helps us deal with all sorts of things by treating them as sequences of events.
RxJS is the JavaScript implementation of ReactiveX.
Why ReactiveX matters.
ReactiveX lets us model just about everything as a stream of events.
An event stream is very similar to an array, except it's asynchronous. So each element in the stream arrives as and when it is generated.
A sequence of mouse clicks can easily be visualised as an event stream.
So can an API call, although it is a stream of a single event. And even regular arrays!
In the end, ReactiveX and RxJS provide a uniform way to deal with asynchronous and synchronous data using a huge number of functions called operators.
RxJS Concepts.
RxJS is a huge library, and is slightly intimidating. It can be overwhelming to go through the documentation and figure out where to start.
This article aims to give you the bare minimum information to get quickly started with RxJS, and hopefully to absorb the idea and whole point of reactivity.
So here goes.
RxJS has four things at its core:
- Observables are streams (or sequences) of events.
- Subscriptions trigger code when an observable generates a new event (addEventListener
behaves like a subscription in this way).
- Observers are what subscribe to the observable (usually they take the form of a handler, or a function, just like the click handler handleClick
we saw earlier).
- Operators are functions which process each event coming from the observable and generate a new observable stream in the process (a bit like map
, filter
, reduce
and other higher order functions).
And that's it. That's the core of RxJS.
This sandbox demonstrates all four of these things. It creates an observable from the clicks coming from a button.
Some Advanced Concepts.
Apart from the four concepts we saw earlier, you'll need to know a couple more things before implementing you own Redux store implementation:
A Subject is like an Observable in many ways, but provides a way for multiple observers to listen easily. Think of them as event emitters.
BehaviourSubject is exactly like a Subject, except it stores the last emitted event. So you could consider it to be stateful.
This statefulness is exactly what we need to implement Redux's store.
And finally, the part you've been waiting for
Redux is a popular state management library, whose main philosophy is that an app's state must come from a single source of truth, named the store.
The store in Redux provides three methods:
Let's try to implement the store and this API using RxJS. We'll use BehaviourSubject
to do that.
Let's start off with a class to define our store interface.
Let's first initialise the state. Since we're using BehaviourSubject
, we just initialise the state to a new BehaviourSubject
with the initial state
The state of the BehaviourSubject
at any given time can be retrieved easily using the value
property. This gives us a natural way to implement getState
The dispatch
is a bit more complex. It takes an action and changes the state according to the reducer. So we can get the next state by calling the reducer with the action. We can then update the state by calling BehaviourSubject.next
The subscribe
method is almost as simple as getState
. Since one can easily subscribe to a BehaviourSubject
by using its subscribe
method, we do just that.
And that's it!
We have created a class that defines the Redux store.
Here's the full implementation, used in a simple todo list app written in React. Notice how I just replace Redux's createStore with my own, and everything just works.
It's important to note that a lot of error handling and special cases have been ignored here, but it really showcases how powerful RxJS can be.
Conclusion
Reactive programming is an incredibly powerful programming model and can help us deal with something as complex as event handling with ease.
RxJS is a library that helps us write apps in such a way. It's powerful enough to let you implement your own Redux store, or any other state management mechanism with it.
It's also worth noting that the reason I was able to swap in my own store so easily in the todo app is because Redux's own API is simple and well defined. Good API design can go a long way in making maintainable software that may require you to swap out components in favour of others that better suit the changing requirements.
Further reading
Book a Discovery Call.