Redux Core Concepts Made Easy

Redux Core Concepts Made Easy

Introduction

This post is the first in a series of three posts to explain the core concepts of Redux, how does it work well with React? and Some cool hooks to make the understanding easier and better. We will be building a small app alongside to realize these concepts better.

Myths

I have noticed that, there are good amount of myths around Redux. See if any of these are familiar to you.

  • Redux is hard, it is difficult to learn!
  • I do not use React, there is no use of Redux!
  • A beginner to web programming can not learn Redux easily!
  • Redux is must for React applications!
  • Redux is more storing common data, like a POJO in Java!
  • ... and Many more..

We will break these Myths as we go ahead with this post and the subsequent ones in the series.

What is State? Why do I need to manage it?

Redux is a client side State Management library. But wait, What is State and why do I need to manage it?

State

A state can be defined as, the outcome of an action performed by user. A state should be described by a data structure so that, state can be understood structurally.

Say, you got a button on a webpage. When click on the button, a network call has been made. Once the call completes successfully, page is loaded with user information and a success message. In this scenario, the state is the user data and the success message like this:

  • User data State:
    {
    'name': 'bob',
    'age': 32,
    'job': 'blogging'
    }
    
  • Success Message State:
    {
     'message': 'The user information has been 
                            updated successfully!'
    }
    

Over the period of time, if the user data gets modified due to some other interaction(like, edit button click), the state changes and hence the data as well.

Without a state management system, it is difficult to know what the state of our application is? We can look at the DOM. We can check DOM elements but please take a note that, State is not as same as DOM. State deals with the actual data representation out of the action been performed and the data is the Source of the Truth.

A State management tool like Redux helps us in creating these data structures and updating them when a new action occurs.

Redux

Let us take an example of a Reactjs app(it can be an Angular or Vue app too) called Jokking. After Login into this app, user sees the list of Jokes, a random Joke, a single selected Joke. User of the app can also search any Jokes and can like them by hitting a button!

As you would have realized by now, we are already dealing with few sets of data.

  • State of logged in: a boolean true or false to indicate if user in a logged-in session.
  • Logged in user information: a plain user object contains, username, full name, email id etc..
  • List of Jokes: An array of Joke objects.

The diagram below shows how these data can flow unidirectional way from one component to another as top-down. As you see, the jokes data needs to flow from App component to 'Jokes' component and downstream. Not only that, Search and Like components also need the jokes data to be operational.

jokking_data_flow.png Data Flow within components could be a nightmare when app grows

It could be really challenging and error prone to maintain and manage the state of the data across components in a meaningful-way once the app grows bigger and larger.

Also each of these components might cause change to the initial data state or create multiple clones based on the usage and need. This is where Redux comes into picture.

  • What if, you can store the data in a centralized place and access from there?
  • What if, there is no way to pollute this data very straight-forward way? As in, the data state is maintained.
  • What if, you can go back in history to see how the data has been changed?
  • What if, as an application developer(or team of developers) got full control on it?
  • What if, your state management becomes more Predictable?

Redux is an open-source JavaScript library for managing application state in Predictable and Flexible ways. State management with Redux is Centralized and it is easily Debuggable.

With this, let us rework on the data flow a bit for our Jokking app. Imagine, there is a single data store where we can keep all the data and maintain their state. The revised diagram will look like this:

Jokkingredux.png A Common Data Store for the data state

Redux Components

Redux helps in managing the state and we know that, the state gets stored and managed in a Store. Hey but,

  • How does the state get updated in the Store?
  • Are there setters and getters like Java POJO?
  • Who updates the state?

Let us start by looking into the following diagram:

redux_flow.png State management using Redux

Now, let us understand each of these components one by one.

Action.png

Actions are the desire of doing something. Please note, actions are more descriptive way of telling what to perform than actually performing it. Actions are responsible for sending data to the store with the help of dispatch and reducers.

In redux, Actions are simple JavaScript functions that returns an object. This object describes the name of the action with a mandatory type property and optionally any input needed to perform the action. An Increment action can be defined as,

const increment = () => {
    return {
        type: 'INCREMENT'
    }
}

reducer.png

Reducers specify how the application's state changes in response to actions sent to the store. Remember that actions only describe what happened, but don't describe how the application's state changes, Reducers does it.

Reducer is a JavaScript function that changes the state based on the Action dispatched to the Store. A reducer for the Increment action:

const counter = (state = 0, action) => {
    switch(action.type) {
        case 'INCREMENT':
            return state + 1;
        default:
            return state;
    }
}

store.png

A store holds the whole state tree of your application. The only way to change the state inside the store is to dispatch an action on it. There is no direct setters available.

A Store can be created as,

import { createStore } from 'redux';

const store = createStore(counter);
// Note: we passed the reducer to create the store.

Once the store creation is done, we can setup the dispatch of Action on it,

store.dispatch(increment());

That's it, you can always subscribe to the store to get what is the current state of your data,

store.subscribe(() => {
    console.log(store.getState());
});

Once you see the entire sequence together, it would look like:

import { createStore } from 'redux';

//Action
const increment = () => {
    return {
        type: 'INCREMENT'
    }
}

//Reducer
const counter = (state = 0, action) => {
    switch(action.type) {
        case 'INCREMENT':
            return state + 1;
        default:
            return state;
    }
}

//Store
const store = createStore(counter);

store.subscribe(() => {
    console.log(store.getState());
});

//Dispatch
store.dispatch(increment());

Conclusion

The example here(Increment a counter) could be a very small one to recognize the power of State Management. When the application grows, data becomes difficult to manage between states, Redux kind of tools are very handy in those cases.

In future posts, we will see how Reactjs and Redux can come together to manage state for a Web Application. We will also see the downside of Redux and when we can avoid it.

Hope the post was a good start for understanding the core concepts of Redux without much difficulties and couple of myths are broken already!

Did you find this article valuable?

Support Tapas Adhikary by becoming a sponsor. Any amount is appreciated!