Blog

React + Redux: when, why and how to use it?

React + Redux: when, why and how to use it?

At Ensolvers, we have been working with React Native at different projects for more than a year, combining the simplicity of React with the state management that Redux provides. In this article we describe a bit of our experience with these technologies.

An intro to Redux

Let’s say you have decided to go with React for your next web project -or React Native for a cross platform mobile application like we did and then you eventually stumble with references or posts about Redux and start wondering what’s all the fuzz: It’s a library or a framework? It’s coupled to React in some way? It persist UI data in some way? Do I need it? etc. I wrote this little article to help you get an initial grasp on the core of Redux and hopefully answer at least some of those questions.

So what is Redux?

Redux can be summarized as a “JavaScript library for application state management”. Or, in other words: it will store state that you consider “global”, so to say. But also it will impose certain rules about how this state is managed: how it can be read and, perhaps one of the key features, how it can be changed.

It can be used with many frontend frameworks (like Angular) or libraries (like React or React Native), it is certainly not a part of React neither it is coupled to it in any way. Its functionality can be extended in many ways (look out for middlewares or selectors).

OK… But why?

For small applications, vanilla React and the setState function, props and callbacks passing combination are OK. But as time passes it is not rare at all that we see frontend applications becoming more and more complex, and this -more often than not- involves managing more state: from caching responses to data created in the UI that is still not persisted along with button states, selected tabs, etc.

In our case we decided to go with Redux to be able to share state between components in a predictable way. At some point we realized it could also be used to decouple components, async services -thanks to something called redux-thunk– and state management, and so we went that way.

Basics

The official Redux documentation mentions three core principles. Briefly those are:

  • Single source of truth: whatever it’s in the store, it’s the true application state
  • State is read only: components can only change state if they declare such intention by what’s called “dispatching an action”. Otherwise, the store state they can request access is expected to be treated as read-only
  • Changes are made with pure functions: officially named “reducers”, they can be a simple JS function that receives the current state and an action, and returns the current state or a new state but never alters any of it’s arguments neither modifies possible global objects

So the basic flow goes like this: a component dispatches an action, the action is reduced according it’s type, and may result in a new state. If that’s the case this new state is sent to the store and then the store notifies all components that have declared interest in such change, possibly causing them to re-render.

A note on global and local state

Though for some of you may seem obvious, maybe it is worth mentioning that not necessarily all state is application/global state. In our case we used Redux for managing state that we considered should really be shared across components and routes, but local state it is by no means forbidden. Also, that discerning what is application state and what should be local/component state may not be as easy as it seems. Certain planning is required and maybe even you’ll find yourself tracing a few steps back until you reach a model that suits your needs, like it happened to us during the first sprints.

Setting Redux up

So, in order to setup Redux we started writing a few new JS modules: one for actions, one for holding the type of such actions -enum like, just for convenience-, one for the reducers and one that wires all that together along with some boilerplate initialization code and creates a new store.

Here’s a few sample actions:

Notice that the removeBook action it’s actually async since it calls the service delBook. It also dispatches many actions along the way. That’s why the implementation differs from the action at the top, which is a simple synchronic action: this last one in turn will be reduced.

Speaking about the devil, here we have a sample of the corresponding reducer:

We see this reducer receives the current state -defaulting to an empty array- and an action. According to the action’s type we’ ve seen above, it will return a new array without the removed book. Note that we followed the third principle: we didn’t mutate the state but instead we returned a new one.

The Provider

Lastly, we wrapped the application main component in a Provider component. This one comes with react-redux and it’s there to keep the store in memory so their child components can access it

Connecting the pieces

To access store state and/or actions a component needs to be connected to the Redux store. This is normally done by simply calling a higher order function conveniently called connect that also comes in the react-redux package. Such function will map the desired application state and/or actions to a given component props.

Testing

Since reducers and actions are mostly simple functions it wasn’t hard to test a complete flow with jest which, for those that haven’t heard of it, it’s a pretty standard tool to run tests on JS projects.

In this test we create a new store with the initial state, we dispatch an async action and when that’s resolved all the asserts begin: from matching the store to a JSON schema to validating that our books collection size has been increased in one.

So how it helped us in our project?

To sum it up in our project Redux allowed us to reduce the amount of props and callbacks passing between components, still maintain a service layer but decoupled from those components: components do not directly request data, they dispatch actions and map the store props they need. And lastly write a few tests that could run both locally and from a pipeline.

If you want to take a look at a working and really simple sample React+Redux project here’s the public repository: https://github.com/francisco-pinchentti/React-basics

2019-08-14 12:30:06 Cats && Stats

At Ensolvers, we love to combine coding and fun whenever we can. This is a screenshot from one of our internal projects: EnsolversTV.
It combines Serverless, React, Bootstrap and New Relic/Youtube APIs in a modular and configurable way to use our several TVs across the office. In this case, we use it to provide real-time monitoring in our projects and, at the same time, let our team delight from real-time lovely cats playing or sleeping in the background.

Love to have fun while coding too? We have several open positions that may be of your interest.

2019-09-10 20:52:40 How to provide transparent request retry in ES 6

How to provide transparent request retry in ES 6

When working for an MVP in one of our projects (a React Native-based app) we were asked to have a “Reconnect” modal dialog with a “Retry” button that would be shown when a request timeouts, preventing the user to interact with an empty UI. The major issue with the initial implementation we wrote was that such button would just simply reload the critical content of the app (some index pages) with no regards for the specific request that had failed or what was the current state of the app.

After the initial release, we decided to improve this behavior and provide a mechanism to retry only the requests that failed because of a timeout. The idea was to recover the state of the app on a successful reconnection transparently, without altering the logic of the services that use our custom HTTP client. The first limitation we have found is that we were bound to use ES6 Fetch API, which at the current moment, among other things, it does not support failure on “hung” connections – i.e., connections that never finish. So what we did is to wrap the original promise returned by fetch within a second one that give us control on how and when to resolve it.

After this improvement, the next challenge was to keep track of the timeout requests and, upon reconnection, retry those again. Just rejecting the promise on a timeout was not an option for us, because this implied that upper level logic reacting to this promise failure would be immediately executed – and that was not the case, since a timeout is not necessarily a failure in an endpoint but more like an unknown state. If the promise was immediately rejected on a timeout, then it will be too late to retry and restore the app state upon a successful request retrial. This meant that with this approach, we would not be able to implement a transparent retrial strategy; we needed a way to, if desirable and even after several retries, resolve the original promise returned to the upper service level so the execution would continue normally after connection restoring.

After debating different approaches internally, our team agreed that a reasonable solution was to queue callbacks to our fetch function itself. In the code shown below, we just modified our wrapped promise to, in the event of a operation timeout, inject an anonymous function that would retry the execution of the same method and propagate the resolve or reject the promises accordingly


So, summarizing, we have different scenarios and outcomes:

  1. If the request is successful, then the wrapped promise is resolved successfully
  2. If the requests fails (for instance, an HTTP status code different than 200 is returned), the wrapped promise is rejected
  3. If the request timeouts, then the execution is queued and a “Reconnect” message is shown to the user.

If case 3 happens one or more times, the showErrorCallback will shown the “Reconnect” message to the user – IMPORTANT: this function must be idempotent. When the user taps on the “Retry” button, the code that executes the retrial (retryFailedRequests, listed below) will be ran and all the queued requests will be retried. Every retry will call fetchWithTimeoutAndQueue and the result of this promise will propagate in chain until reaching the top promise which, once resolved, will execute the real code.


Now, whenever the app loses connection it will be effectively paused until a successful request is made. Then, each service that has attempted a request will continue with normal execution.

This is exactly the behavior we were looking for, so we should be good to go, right?. Well, almost. Since we are queuing multiple requests, there is a good probability of them being identical to each other. So, if these requests were idempotent, we could add some simple sanitization in a way that repeated ones are filtered out, and even add an amount limit to the queue itself. Our final implementation included these and other improvements.

2019-09-23 17:22:53 Automating office tasks using Slack bots

Automating office tasks using Slack bots

Automation allows to do a lot of things faster, even repetitive office tasks. If you are using Slack as a communication tool, using bots may save you a lot of time, specifically in regards to administrative tasks – and we have proven this with a real world example.

On Fridays we order lunch for the whole team using an old-school approach: a spreadsheet that required manual data entry, which was prone to errors. The most important part of this process was to keep track of the orders in a way in which every team member would be able to request a specific meal only once and also ensure that team members would not overwrite each others’ meals. So we decided to implement a bot to simplify this process.

Solving the routine task using a Slack app

From a user’s point of view, we would like the bot interaction to behave in the same way a restaurant’s waiter/waitress does when it received customers:

  1. The waiter/waitress shows the menu,
  2. The client makes an order
  3. If the order has not been confirmed, it can be edited, refined or cancelled
  4. All the orders can be listed all the times that is required – in our case, it was required to send all orders to our lunch provider.

Our bot is architectured in three basic pieces

  1. Configure Slack to declare the commands required
  2. Configure Slack to respond to users’ orders
  3. A REST API that answers to Slack requests and stores the orders in our backend

Step 1: Defining the Slack command

This can be easily done through the Slack UI, specifying the command name and the URL that will be hit when the command is triggered

Step 2: First response when a user triggers the command

The conversation starts when a user triggers an action using slash command “/lunch-menu”. As described in the previous step, this hits our REST API, which returns another message (a JSON content) with the action and meal selection user interface that allows a user to choose an option for luch. As a user interface, we decided to show a list of the different meals and an “Order” button using Slack message buttons https://api.slack.com/docs/message-buttons

On the backend side, the code that generates the interactive UI using Slack API (https://api.slack.com/messaging/interactivity) is listed below.

IMPORTANT NOTE: before using message buttons, interactive components support has to be enabled in Slack

Step 3: First response when a user triggers the command

Once the UI is rendered, the user just presses the “Order” button that matches her/his desired meal, which in turn will hit the REST API with the necessary information – in this case, basically the name of the meal requested by the user. The REST API now processes the lunch order and return the result of operation

As a result, Slack will send a JSON payload through an HTTP POST request to our API, encoded as a field named payload in a form (content type application/x-www-urlencoded).


To process the result, we need to grab the URL-encoded content of the payload field and parse it – we have used the Jackson JSON Library (https://github.com/FasterXML/jackson) to parse such payload. In the Slack API context, callback_id acts like a topic about the context you are handling. ref: https://api.slack.com/docs/interactive-message-field-guide:


The only remaining piece is the order listing that it is very similar to the flow described in Step 1. For this last use case, we defined a new command called /list-orders, that generates the list of meals and the quantities ordered by our team members.

With this last command, our bot is complete from the functional perspective. Any other new interaction can be added just creating new commands and including the proper responses in our REST API.

Compartir el post