Redux

Khusboo Kumari
7 min readOct 6, 2021

All you need to know to get started

History

Redux was born as a system to manage global app state before React released a more stable public version of Context-API. So now you get an idea that Redux was born when Context-Api was not stable hence not suggested by React either during the early years of Context-API. Under the hood, Redux uses the Context-API to power its own system. Well, Redux & Context Api are two different ways to solve the same problem.

Definition

Redux is a state management tool.

Why Redux if React was already handling the states?

  1. How to handle the state that your whole application needs?

i.e. Managing states from different components without constantly lifting up the states higher and higher in our application until the whole of the application has access to it.

2. Lack of organization and clarity around states in React application.

i.e. If states are set poorly then it can affect other states thus triggering a chain of state changes and UI changes. React can handle these situations but it can be difficult to follow up in large and complex applications.

Guiding Principles

  1. A single source of truth(“global state”).

i.e. Redux solves the complexity of states problems by having you outsource all of your data needs to the global state.

2. State is read-only (“actions”).

i.e. If a component needs to change a state the global state in Redux, the only thing it can do is to emit an action that describes the type of change it wants. In other terms, it hands over the action to Redux, and lets Redux figure out how to do make the state change.

3. Changes are made with pure functions(“reducers”).

i.e. Pure functions are defined by two things — a.) If a function is called with the same parameter, it will return the same result each time. b.) It won’t make any change outside of itself. Hence, nothing else is modified as a result of calling your function

So, reducer takes the previous version of the state and an action and determine a new value for the state without modifying the old version of the state

Fundamentals

  1. Action & action creators
  2. Dispatch
  3. Reducers
  4. Store

Understand this image with a Restaurant Analogy

  1. Your Order -> “action”

i.e. Your food Order(action) is the description of what you want to achieve.

2. Restaurant server -> “dispatch”

i.e. You give your order to the waiters(dispatch) whose job is to take your order(action) to the chef(reducer).

3. Chef -> “reducer”

i.e. The chef's job is to take the order(action) and produce something in response(global state) to it.

Understanding the Fundamentals using plain JS

  1. Actions

Action is a simple object, with a type property whose value is a description of the kind of change you want to make in the state

const redux = require("redux") 
const action = {
type: "INCREMENT"
}

2. Action Creators

Usually, we don’t prefer to create just an action variable, instead, we create action creators.

const redux = require("redux")
function increment() {
return {
type: "INCREMENT"
}
}
console.log(increment())//check

3. Reducer

Reducer return a new state based on the incoming action.type

const redux = require("redux")
function increment() {
return {
type: "INCREMENT"
}
}
function decrement() {
return {
type: "DECREMENT"
}
}
function reducer(state = {count: 0}, action) {
// return new state based on the incoming action.type
switch(action.type) {
case "INCREMENT":
return {
count: state.count + 1
}
case "DECREMENT":
return {
count: state.count - 1
}
default:
return state
}
}

4. Store

Creating store is where you actually start using the redux library. All the above code is just a philosophy, here comes some real deal.

//to the above code snippet add the following line at the bottom to create a store which takes reducer as a parameter.const store = redux.createStore(reducer)
console.log(store)//check

Store is an object with 4 methods:

{dispatch:
dispatch(action)
, subscribe:
subscribe(listener)
, getState:
getState()
, replaceReducer:
replaceReducer(nextReducer)
}

Subscribe

Subscribe is method that allows us to pass a function to it, which performs desired task after a change is made to the store. In short, subscribing to the store changes, and if desired change ever occurs then it will run the function that we have provided.

const store = redux.createStore(reducer)
store.subscribe(() => {
//some code
})

getState

This method is used to get the current state of our application’s data.

const store = redux.createStore(reducer)
store.subscribe(() => {
console.log(store.getState())
})

dispatch

This method takes the action that we have provided to the reducer. The reducer then takes that action, look at its type property and determine the new state to return

const store = redux.createStore(reducer)
store.subscribe(() => {})
//dispatch
store.dispatch({type: "INCREMENT"})//but we don't prefer to pass action like this, since the magic string is hardcoded and with slight mistake things could go wrong

Payload:

Sometimes, the action type isn’t indicative enough about the operation to be taken place. Payload is just an amount/data that makes the action more informative and generic. It helps to reduce the number of action creators

const redux = require("redux")//Just one action creator for both increment and decrement
function changeCount(amount) {
return {
type: "CHANGE_COUNT",
payload: amount
}
}
function reducer(state = {count: 0}, action) {
switch(action.type) {
case "CHANGE_COUNT":
return {
count: state.count + action.payload
}
default:
return state
}
}
const store = redux.createStore(reducer)
store.subscribe(() => {
console.log(store.getState())
})
store.dispatch(increment(5))

CombineReducers:

Code becomes complex if we let only one reducer manage many different parts of the state. CombineReducers come in handy and help us to split the reducer apart into multiple reducers and have each one of them in charge of one part of the state.

//For  instance, see the following state. We can have three separate reducers for count, favoriteThings, votes, respectivelyconst initialState = {
count: 0,
favoriteThings: [],
youTubeVideo: {
title: "",
viewCount: 0,
votes: {
up: 0,
down: 0
}
}
}

To see a detailed example of CombineReducers, go through the code and see the console for results.

https://codesandbox.io/s/github/khush611/combinereducers/tree/main/?file=/src/index.js

Redux in React

Provider:

We are going to follow the Provider pattern which simply means we are going to wrap our App in Provider component just like Context API. Now recall what I told earlier that “ Redux uses Context Api under the hood to provide values to the application”. Provider takes store as a prop.

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById("root")
)

Connect:

react-redux comes with a function called connect that act likes glue to connect the redux store and your component.

How does connect work?

1. Higher-order component

2. Pass 2 things:

a. “What parts of the global state does this component want access to?”

b. “What actions do you want to be able to dispatch from this component?”

It then returns a function to which you pass the component you want to

connect. When called, this function creates a new component wrapping yours

which passes the global state and “dispatchable” actions to your component

via props.

How connect works?

connect (“What parts of the state do you want?”, “What actions do you want to dispatch?”) (Component)

connect(mapStateToProps, mapDispatchToProps)(Component)

mapStateToProps :

A function that returns an object where the keys are the name of the prop your component wants, values are the actual parts of the global state your component wants.

function App(props) {
return (
<div>
<h1>{props.count}</h1>
</div>
)
}
const mapStateToProps = (globalState) => ({count: globalState})

mapDispatchToProps :

A function that returns an object where the keys are the name of the prop your component wants, values are the actions that we want our reducer to dispatch.

import {increment, decrement} from "./redux"//import action creators
function App(props) {
return (
<div>
<h1>{props.count}</h1>
<button onClick={props.decrease}>-</button>
<button onClick={props.increase}>+</button>
</div>
)
}
const mapDispatchToProps = {
increase: increment,
decrease: decrement
}

connect can also be written as :

connect(state => ({count: state}), {increment, decrement})(App)

Hooks:- useSelector :

useSelector is a replacement to mapStateToProps and it does work in less code.

import React from "react"
import {useSelector} from "react-redux"
import {increment, decrement} from "./redux"
function App(props) {
const count = useSelector(state => state.count)
// state is an obj of states
return (
<div>
<h1>{count}</h1>
</div>
)
}
export default App

Hooks:- useDispatch :

useDispatch is a replacement to mapDispatchToProps and it does work in less code.

import {useSelector, useDispatch} from "react-redux"
import {increment, decrement} from "./redux"
function App(props) {
const count = useSelector(state => state)
const dispatch = useDispatch()
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(increment())}>+</button>
</div>
)
}
export default App

Before you start using the hooks and replace connect, you must know that for testing purposes it is suggested that should be a separation between react and the component which is achieved through connect. But using hooks forms a tight coupling between the redux and the component. So decide wisely according to your requirement.

Redux Thunk :

Thunk comes from the idea- a function that returns a function. It lets action creator perform asynchronous operations like API calls. A small example to demonstrate how redux work is given below:

https://codesandbox.io/s/github/khush611/redux_in_react_redux_thunk/tree/main/

It shows how asynchronous operation has taken place in increment action creator since thunk allows action creator to return a function with the dispatcher.

Conclusion

This post is highly inspired by Bob Ziroll’s teaching 🙌 😇. Hope you all got something new to learn, feel free to share valuable responses and share this article with your developer friends. Happy Coding 💻

THANK YOU!!!

--

--

Khusboo Kumari

Software Engineer | Environment & Animal Lover | Front End Enthusiast