Reactivity with Redux and Meteor
One of the tenants of MeteorJS is “Full Stack Reactivity”, and over time this has been shown with examples of real-time web applications: Uber, Instant messaging, and real-time collaboration to point out a few. But what if the product you’re building, the problem you’re trying to solve, isn’t in the same class as the ones mentioned above? The truth, is there is a difference between “reactive” and “real-time”.
What is Real Time?
Real time web applications use a collection of technologies which allow your users to receive data over the network as soon as it has been invalidated. This usually means your software has to constantly poll it’s data sources to keep data fresh and up to date. From experience, Meteor achieves this by using web-sockets to push data “over the wire”, and by using Mongo op-log to tail the latest updates of your database. This helps your users keep up to date with information at all times.
What is Reactive?
Reactive web applications are built on four guiding principles. Reactive applications are:
- Responsive — it responds to stimuli of the system.
- Scalable — it’s patterns can scale to multiple parts of your system
- Resilient — in times of failure, the system still provides responsive behavior to it’s users
- Message-Driven— the stimuli are produced by user driven behavior or event based behavior.
More on Reactive programming here.
Most of the time our applications need to be Reactive not Real-time. And, most of the time, your application doesn’t need to spend the performance cost of operating at real-time if your users nor the problem you solve care for it at all.
Taking this approach to Meteor
Today, in traditional Meteor applications, a Pub/Sub pattern via Meteor’s live-query system provides the real-time api you need to build applications like Uber or Lyft.
So we can build Meteor applications that may need live-query to power our real time features, but how do we build the 90%(in some cases) of the application that do not have this need for “real-time”-ness?
Enter Meteor Methods
I’ve been championing Meteor Methods lately, and soon converting all your “reactive” needs to the Apollo Stack.
Before we continue let’s do some plugs:
That’ll get you started and is my recommendation instead of doing what I’m about to explain below.
In Meteor, you can use Methods to fetch data from the server and not have live-query constantly watch the data returned by them. Methods in Meteor are primarily used for mutations, but many big products, Workpop included, have been using Meteor methods for non-real time data fetching (thus you should use Apollo Stack :]).
The downside of this approach is the lack of “reactivity” that naturally is associated with plain JS Object payloads.
This is where Redux comes in. Because there are already patterns in the Redux community dealing with Asynchronous requests fetching data we can borrow these patterns for use in our Meteor applications.
Writing some code
First let’s handle the Async pattern in Meteor. Using “redux-thunk” our Redux store can dispatch functions to handle our asynchronous action. A simple example can be shown below:
When our method’s callback returns we assess if there was an error or result. If error, we dispatch to our store an error action to notify all of our UI that an error has occurred, upholding both our responsive and resilient accords of reactive programming. The dispatch process is the message driven principle and Redux can and HAS scaled to huge products. Just check out the list of companies using it here.
But what about Optimistic UI?
The problem with our example above is we as developers have no guarantee the response time of the remote call we made above. What if the user is waiting 30 seconds before seeing any updates on their screen. For one, they would think your app is slow. You may lose your customers too! Mo latency Mo Problems!
So if we can’t guarantee response times, us front-end developers need to implement Optimistic Updates: we need to make local changes on the assumption that a remote operation will succeed.
We can make a couple changes to the code above:
In this version, we dispatch to our store right away. We essentially then call and forget. If there’s an error we reset the state back to the reference we stored of the post state in the beginning of the call.
Now instead of using redux-thunk, we can just dispatch our method like so:
There are also some existing libraries that can help you achieve optimistic updates:
Don’t need real time? No problem. Redux can help ease the load from your servers and provide a nice predictable method for reactive programming in your applications.