Everything Redux — Part 1

Francisco Leal
Runtime Revolution
Published in
5 min readMay 3, 2018

--

This series of posts aims to show how redux works and the different possibilities that it can bring to your application.

Photo by Émile Perron on Unsplash

Redux is a predictable state container for JavaScript apps.

This is the first sentence on the Redux website, and it perfectly describes what Redux is and what we can expect from it. I started using Redux back in September 2017, initially with Angular2 and, afterwards, with React Native while building mobile applications. In all those projects Redux boosted the development speed, reduced the amount of effort to produce new features and mostly helped our code to stay readable and clean.

Redux depends on some core concepts: Actions, Reducers and Store. This is what I aim to explain in Part I. Let’s dive into it.

Actions

Actions are meant to be thought of as facts, facts about what happened in your app and where they happened. Actions are plain Javascript objects that are characterised by a type and typically a payload. Actions are also the only way to make changes to the Redux state.

In my first project we always prefixed our action types with the name of the module or component where that action was being created, this helped a lot with debugging and logging, since so much information is already present in the action type, so I’d recommend you do so as well. Action Creators are essentially what the name says they are, they are functions that create the actions that Redux is expecting to receive.

The way to use these action creators in your application is by dispatching those actions through use of the dispatch() function. We can access the dispatch through the store directly store.dispatch() or by using a helper, such as connect() in React’s case .

Reducers

Within Redux all of the state is stored inside a single object, and it will be through this state that we have access to the information our application will need. As such, making sure that the structure of our state is well thought out in advance is of extreme importance. Some important concepts that you should think about at this point depend on how big the application you’re aiming to build is. If the application has to manage a lot of different states and has a lot of references between different entities you should have a look into data normalisation — Redux has an excellent page on this.

Reducers are pure functions. Reducers should not have any side-effects! There are specific ways to handle calling an API or performing non-pure logic. The reason for this is that we want to assure the predictability of our state changes and our app. We want it to be so that for the same state and the same action, the new resulting state will always be the same. If we introduce API calls in our reducer there can always be network errors, server downtime, etc and we won’t end up with the same state as the data may not be available or be wrong. This is a no-go for our goals.

If you want to start looking into side-effects here are some places to start looking. However these are more advanced topics which I aim to cover in Part II of this post:

  1. redux-thunk
  2. redux-saga
  3. redux-observables

So the general idea of a reducer is to take a certain action and the current state to generate a new state.

(action, state) => nextState // general idea behind reducers

Reducers use the action type in order to identify what type of changes should occur on the state.

We define our initial state and then create the reducer. If the action type is not the one we are expecting then we just return the same state that we started with. I make use of the spread operator in order to merge the new toDo item and then to generate the new state. The spread operator makes sure that we are creating a new reference to the state and therefore we can easily have our components understand that something in our state changed. Immutable.js can be a healthy addition to your project if this concept is new to you or you want to make use of immutable data structures across your application as well.

Store

The store allows us to access the state through getState(), dispatching actions from anywhere in your application through dispatch() and subscribing to changes that occurred on your state with subscribe(). As we mentioned before, if you are working with React, some of this underlying work is abstracted from you. By using connect(), mapStateToProps and mapDispatchToProps, we are abstracting getState(), subscribe() and dispatch().

Let’s take the example we had before and create a store by passing in the reducer and then let’s access the store and retrieve our toDoList.

Here we can see both getState() and dispatch() working. One thing to note is that, if we have a complex state with a lot of nesting, retrieving key pieces of information from the state can become troublesome and hard to maintain. Should we ever need to refactor some of our state we’ll have to update everywhere it is being used and it is easy to introduce new errors and bugs while doing so.

Selectors to the rescue!

The Reselect library best describes what selectors are and why they are important.

Selectors can compute derived data, allowing Redux to store the minimal possible state.

Selectors are efficient. A selector is not recomputed unless one of its arguments changes.

Selectors are composable. They can be used as input to other selectors.

The example we are using is really simple, so our selectors won’t seem like much. But let’s create them nonetheless.

We can already start to see the power that selectors brings us. Unless our list changes, which means new items get pushed in or item are popped, the selector won’t have to recalculate the mapping in order to get us the dates of our ToDoList. It knows that since the argument has not changed, then the output is still the same as before.

Using selectors has made our code more readable, shorter and less prone to mistakes if we need to change some logic. Oh and did I mention easier to test? Having our logic to retrieve information for our state in separate functions, we can extensively test both our state as the values that our UI will receive and make sure we are ready to handle them.

This is it for part I, short but concise. In part II we’ll take Redux to the next level by introducing side-effects. We’ll take a look into the differences between redux-thunk, redux-saga and redux-observables to understand how each works. If you have any questions, please let me know!

I love building products and I found my place to do so at Runtime-Revolution. If you are interested in who we are and what we do, make sure to reach out!

--

--