Redux

Redux is an open-source JavaScript library for managing application state.

Basically, different components of the UI have their state dependent on a central place, where, if you change data, you start seeing changes in the UI components.

It is the most popular solution for state management in all JavaScript frontend applications whether they be in React, Angular, Vue, Svelte or just plain'ol Javascript

It works on the fundamentals of functional programming where usage of pure functions is done to prevent any mutation of data to

  1. Have a single source of truth
  2. Perform parallel reads/writes to the store for increased speed
  3. Redux dev tools => A chrome extension which offers amazing insights on state changes and the resulting UI updates in your application.

More on functional programming and object immutability can be found brilliantly here :

Pure functions, immutability and other software superpowers
Pure functions are without a doubt the most important technique for writing software that I have learnt thus far in my career. This is because they help us simplify our code and make the effects of…
Redux Tutorial - Learn Redux from Scratch
Redux tutorial - Learn redux from scratch. 🚀Get the full Redux course: https://codewithmosh.com/p/ultimate-redux👍Subscribe for more tutorials like this: ht...

There are just 4 basic interacting concepts in Redux

STORE =>

  1. A centralised place where all the reactive data is stored and updated.
  2. A state in Redux simply refers to a snapshot of the store at a particular instance

ACTION =>

  1. This is basically just an object describing what needs to be changed in the store based on some interaction of the user with the UI.
  2. These are dispatched through a common line and given a payload and a type to tell the reducer or underlying middlewares (such as logging) what needs to be done.

REDUCER => This is just a function that defines the stores updates, based on the action object received

4 Steps to follow while designing a Redux store

  1. Design the store  ⇒ Decide what you wanna keep in the store
  2. Design the actions ⇒ What are the actions that the user can perform in this app
  3. Create one or more reducers ⇒ Take in action, update state
  4. Set up the store ⇒ Update the store, based on the reducer

Mini Project

Here, we will be creating a small bug tracking application to understand how a redux store is designed and implemented based on the requirements.

  1. actionTypes.js => This file will simply help you keep track of what actions are available in your store. Also, by storing actions options as variables instead of strings, we reduce the chance of spelling errors and mismatches while writing code later
// ACTION TYPES
export const BUG_ADDED = "bugAdded"
export const BUG_REMOVED = "bugRemoved"
export const BUG_RESOLVED = "bugResolved"
a

2. actionCreators.js => This file basically defines functions to create action objects. The functions are something that can be called from the UI  interactions and the action objects created basically involve 2 main properties

  • type : One of the action types chosen from the options listed above
  • payload : Some data that needs to be passed along to help the functions processing in the background (reducer and middleware functions) to process the action
import * as actions from './actionTypes'

export const bugAdded = (desc) =>
{
    type: actions.BUG_ADDED,
    payload:{
        desc
    }
}

export const bugRemoved = (id) => ({
    type: actions.BUG_REMOVED,
    payload: {
        id:id
    }
})

export const bugResolved = (id =>
{
    type: actions.BUG_ADDED,
    payload:{
        id,
        desc:`Bug ${id} was resolvedd `
    }
})

2. reducer.js => This file defines what mutations must be performed on the store when an action of a certain type is dispatched.

let lastId = 0;
const reducer = (state=[], action => {
	switch(action.type){
		case actions.BUG_ADDED:
            return [
                ...state,
                {
                    id: ++lastId,
                    desc: action.payload.desc,
                    resolved:false
                }
            ]
        case actions.BUG_REMOVED:
            return state.filter(state.id !== action.payload.id )
        case actions.BUG_RESOLVED:
            return state.map((bug) => 
                bug.id !== action.payload.id
                    ? bug
                    : {
                        ...bug,
                        desc: action.payload.desc,
                        resolved:true
                    }
            )
    
    }
} )

3.  store.js => This file involves creation of a store that follows the norms set forth by the reducer and the action files.

The window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION() parameter is just passed to the createStore method to sync it with the chrome extentsion - Redux Dev Tools

import { createStore } from 'redux'
import reducer from './reducer'

// Install the Google Chrome Extension -> redux dev tools
const createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION())

export default store

5. index.js => Just an arbitrary example of how any file can subscribe to the store updates and pass actions to it.

import store from './store'
import { bugAdded, bugRemoved } from './actionCreators.js'

const unsubscribe = store.subscribe(() =>
{
    console.log('State was just changed !', store.getState())
})

// Adding a bug
store.dispatch(bugAdded('Bug 1 encountered'))

// Removing a bug
store.dispatch(bugRemoved(1))

// Resolving a specific bug
store.dispatch(bugResolved(1))

unsubscribe()

NOTE : Combining reducers

Sometimes you may wish for > 1 reducers to operate on the store. This is where you come in and combine them both into one and push it to the store.

import 'reducer1' from '...'
import 'reducer2' from '...'

const allReducers1 = combineReducers({
	red1:reducer1,
	red2:reducer2
})

Conclusion

Congrats ! You have everything you need now to become a next level frontend engineer. Redux may be painfully verbose but it's undeniably the most powerful tool for state management in production level applications