The official documentation says that Redux is a "predictable State container for Javascript applications". This means that Redux makes it easy to manage all the data in your application in just one place, instead of having it being in a bunch of different components. However, even if this does simplify things somewhat, it can get messy if you don't keep some basic principles in mind.

This article is written using Redux together with React in mind, but these principles apply to any project with any other javascript view library or framework.

Redux has three core principles as described by his co-author Dan Abramov, and the first step to becoming a Redux expert is to fully understand them. In this post we are going to explain each one of them in detail.

To picture the basic principles of Redux better, we are going to use a simple Pizza Calculator App. The inputs for our application will be the number of guests that we will have at our party and the calculator will tell us how many pizzas we need to buy. It is a very simple example, but it can help us perfectly picture the principles of Redux with it. Keep in mind these principles will stay the same as your application grows bigger and more complex.

Pizza Calculator Example App

Principle #1: Everything is contained in a single object

Redux is the State of your application, and the State is everything that could potentially change at any given point in time inside your app. This State is contained in a single Javascript object. It is also called the State Tree.

The only things that can change over time in our app are number of people and number of pizzas. The first one is input by the user and the second one is calculated by the app. Those are the two values that we are going to store in our State tree. With the current implementation we could have number of pizzas directly in the State of the Component, but for the sake of this example we are going to keep it in the State Tree.

State Tree of the Pizza Calculator App

This is the whole State of our application, kept in a single object in the Redux store that you can grow as large as your application needs it.

Principle #2: The State Tree is read-only

Here is where the concept of an action comes in. Every time that you want to modify the State of your application, you need to dispatch an action, which will describe the change that is about to happen.

An action is a plain Javascript object and it has information on the change that will happen on the State. The only requirement of an action is that it must have a type property with a value assigned different than undefined. It is recommended that you use a string, and it should be as descriptive as possible. It helps a lot when you are debugging your application.

To picture this better, I wrote a simple logger.js file which logs the current State to the console, the action describing the change to be made to the store (action), and the State after the action was dispatched. For now, we will only see the action.

Dispatched action to change the State

In the action depicted in the previous image, we can see that the type is UPDATE_NUMBER_OF_PEOPLE, which is a short description of how the State will change, and then the payload has the value "6". By reading the action object it is easy to infer that the number of people invited to our party will be 6.

Actions are the only way that we can change our State Tree, there is no other way. The State is read-only, we can't modify it directly.
It is important to know that it is a good practice to make only one change to your State Tree per action. This way it is easier to track what is happening in our application which can also help prevent bugs.

Principle #3: The Reducer must be a pure function

The reducer is a pure function that you need to write and will be used by Redux to calculate your next State object based on two parameters, an action describing the change to be made and the previous State.

A pure function is a "reliable" function that always returns the same result if the input is the same, without observable side effects

This pure function called reducer does not mutates the State. This means that every time you dispatch an action, Redux returns an entirely new State, regardless of how many properties the actions has changed. This process is always the same, no matter if your application is a "Pizza calculator" or a much more complex one.

If you are wondering if it is expensive to calculate the whole State of your app in a single function every time that there is a change, it is not! For example, if I change the number of people in my app, I have to create a new object for the State, but I can keep the reference to the previous version of the number of pizzas, because it has not changed when I changed the number of people. This is what makes Redux fast.

This is an example of how Redux calculates our next State. We need to send to our reducer an action and the previous State. At doing this, Redux knows that the number of Pizzas will not change, it will remain as 4, but what it needs to change is the number of people, and its new value will be 13.

These are the three basic principles of Redux

  • Everything is contained in a single State object
  • The State tree is read-only
  • The Reducer must be a pure function

It is important to master these concepts in order to understand and build an efficient Redux application. As long as you follow these principles, you will have a solid Redux foundation to start building more complex applications.