Redux 101

January 10, 2020

This is part one of two Redux mini-series.

Why I wrote this

Redux is a big name if you are a React developer. In the beginning when I tried to learn it, I struggled to understand it. Even the basic tutorials were hard to understand because they contained terms I didn't know then: reducers, actions, store, pure functions, etc etc 🤷‍♂️🤷‍♀️.

Now that I have used it for some time (big thanks for my coworkers who guided me), I want to help people to understand Redux.

My hope is by the end of this article, you will know:

  1. The problem with React without state management
  2. What Redux is solving
  3. What reducer, store, initialState, and action are

The concept also applies to any state management library like Vuex. So even if you are not a React / Redux developer, this post may help you.

The problem with React without state management

The first question I had when I learned about Redux was, "Why do I even need it?"

It is helpful to know what problem Redux solves to understand it. Redux helps you to manage your application states. Redux site says that Redux is a "A Predictable State Container for JS Apps". What does that even mean?

Imagine a page in a React app that has a form and a button. You fill out a form, then you click the button. A few things happen: the button turns red and the form hides.

Pic1 - image of form and button

This page is made out of two React component: Form.jsx and Button.jsx. Remember, components are reusable. It is important to keep them separate so we can reuse Button.jsx in different places when we need it.

Back to our app. Here we have a problem: How will our button tell our form to go hide? They are neither sibling nor parent/child either. 🤷‍♂️

Here is the problem we are facing working with stateful framework like React. It has many components that don't know about each other. It can get really tricky to make one component to change the state of the other component.

The problem Redux solves

Redux is a state management library. Using Redux, button can now access and change isHidden that form uses. How does Redux do it?

Redux is a command center. This command center has a storage that STORES states. Among these states are our color and isHidden.

Our app may have initial states like this:

{
  buttonText: 'Submit',
  buttonColor: 'blue',
  isHidden: false,
  awesomeNotes: [
    {title: 'awsome!', id: 1},
    {title: 'awesomer!', id: 2}
  ]
  ...
}

Every component that is CONNECTED to our store has access to it. Our form can see everything in the store, including isHidden and buttonColor. Our button can see everything in store, including isHidden and buttonColor.

Because all important states are centralized, they can be shared to different components to be used and updated.

When we click the button, imagine the button submitting a request to command center: "Hey command center, can you CHANGE_BUTTON_COLOR to red and TOGGLE_FORM_IS_HIDDEN?"

Pic2 - image of button dispatching actions

When command center receives the request requests, it processes the request from button. It updates those buttonColor to red and isHidden to true in store.

Pic3 - image of command center processing

Our state in our store now looks like this:

{
  buttonText: 'Submit',
  buttonColor: 'red',
  isHidden: true,
  awesomeNotes: [
    {title: 'awsome!', id: 1},
    {title: 'awesomer!', id: 2}
  ]
  ...
}

When the state changes, since button and form are CONNECTED to store, it re-renders with new states. Button is now visibly red and form is now hidden.

I skip a step here. Earlier I mentioned that button made a request to command center. When command center receives the request, it doesn't quite know what to do with the request. Imagine button only speaks Spanish and command center only speaks English. We ned someone in the command center who knows English AND Spanish to translate it into something that command center can understand!

This translation from button request into something that command center can understand is done by REDUCER. In React, the request from button may look like this:

{
  type: 'TOGGLE_FORM_IS_HIDDEN',
}

A request may contain argument(s):

{
  type: 'CHANGE_BUTTON_COLOR',
  color: 'red'
}

This request, in Redux's term, is called ACTION.

Back to our analogy, command center finally receives something he understands. Thanks to our translator, the request "TOGGLE_FORM_IS_HIDDEN" and "CHANGE_BUTTON_COLOR" can be understood by command center. He knows exactly what to do.

For example, when receiving request 'TOGGLE_FORM_IS_HIDDEN', command center does:

  1. He finds isHidden from state
  2. He toggles it to opposite whatever it was before.
  3. The remaining states on button and awesomeNotes is not part of the 'TOGGLE_FORM_IS_HIDDEN', so he leaves them alone.
  4. When command center is done executing the request, it returns the states with isHidden updated.

Button sees that buttonColor has a new state ("red") and form sees that isHidden has new state (true). Since state is updated, React re-renders. That's why we see the button changes color and form goes into hiding.

Pic4 - image of button turning red and form hiding

That's the basic analogy how Redux works.

Four important concepts about Redux

There are four concepts about Redux, mentioned above, that are important for it to work:

  • Initial states
  • Actions
  • Reducers
  • Store

Initial States

Initial states are the states at the start of our application. The button was initially blue and form was not hidden (isHidden: false) for example. When we refresh the app, Redux loses all updated states and reverts back to initial state.

Actions

The requests from button were actions. Actions are events. An action is nothing but an object. At minimum, an action must contain a type.

{
  type: "CHANGE_BUTTON_COLOR",
  color: "red"
}

When button requests "CHANGE_BUTTON_COLOR" on click, we call it dispatching an action.

Reducers

Reducer is the guy who speaks Spanish and English and helps command center to understand the requests. Technically, a reducer also performs the action (Reducer is both the translator AND command center).

It took me longer to grasp what reducer was, so I will elaborate more here:

Let's say our reducer understand two actions: "ADD_NOTE" and "DELETE_NOTE". Our reducer looks like this (the switch case usage normal):

  switch(action.type){
    case ADD_NOTE:
      return [...state, action.note]

    case DELETE_NOTE:
      // return logic to delete note

    default:
      return state;
  }

The action might look like this:

{
  type: "ADD_NOTE",
  note: "This is my awesome note!",
}

Our reducer checks the type (action.type) and finds a match ("ADD_NOTE"). It returns an updated state: [...state, action.note] (previous state plus the newest note)

If you send this reducer "UPDATE_NOTE" action, it does not know what to do. It will simply default state (default). You can add as many different case scenarios as you want here.

In short, a reducer has a set of instructions. When it receives an action, it looks for matching type. When it finds a match, it does whatever that instruction is set to and returns the modified state. Keep in mind that state is immutable. We are not directly changing the states array. We are returning a new array of notes consisting of the old notes plus the new note.

Again, do not mutate the actual states. Return a copy of updated states.

Store

Store is where the states are being stored. Think of a giant storage with security guard outside. We cannot directly go to the store and modify the value. The security guard won't let you. You need a special permit. That permit is called action dispatch. Only by dispatching the security guard will let you update the store.

A store might look something like this:

{
  buttonText: 'Submit',
  buttonColor: 'blue',
  isHidden: false,
  awesomeNotes: [
    {title: 'awsome!', id: 1},
    {title: 'awesomer!', id: 2}
  ]
  ...
}

This should cover basic Redux. There are still more into Redux that I haven't covered. Hopefully this is enough to get you started with Redux.

Next time, we will create a simple React / Redux app! You can find the next tutorial 👉here👈.

Thank you so much for reading this far. I really appreciate it. Please let me know if you find any mistakes/ have suggestions how I can make this better to better serve you guys! 👍

© Copyright 2021 Igor Irianto