DEV Community

Cover image for Understanding Redux without React
bhupendra
bhupendra

Posted on

Understanding Redux without React

I always use to talk about react and redux in the same breath and thought redux does not exist without react. This was a big misconception that was cleared by responses to my tweet :
image.
In this post I will share how to learn redux in isolation and that will answer the question is Redux relevant today ?

What is Redux

Redux is predictable state container for JS Apps as per official docs, let's break down this definition :

  • Predictable : State changes to application is predictable, which can be tracked over time (time travel)
  • State Container: Redux stores the state of our application. App State means state represented by all the individual components of the application
  • JS Apps : Redux can be used with any UI library(React/Vue/Angular/Vanilla...), this was unclear to me

Why Redux

Let's see how complex state management can be without Redux
image
Components manage their State internally, but when there is a need of communication of state between different components then we need to lift the state up to common ancestor component and then drill it down to the component which needs it.
In above ex: name state (+ setter method) is managed by Component C , then D requires it , we lift to A , but suppose Component F requires it then we need to move to App Component and then pass it down to Component F. This state management becomes messy and complex as the App grows.

You might think this is classical example of Props Drilling and can be solved by Context, then here is a great article on it.

Now lets figure out how Redux can simply above state management process :
image
Redux maintains a centralized store which holds state of app, each component which have subscribed the store , receive the updated state. We will look into the complete flow of Redux in next section.

Real Life Example

All of us, would have visited a Bank at least once in our life for depositing / withdrawal/ etc... We don't go to bank's vault directly but ask to the cashier, where the bank staff handles operation for us. We give deposit/withdraw request by filling a slip and giving it cashier. Let's think this scenario in terms of Redux :

  • Bank's Vault is the store which stores all the money
  • Cashier is the Reducer which executes users action to update money in the vault
  • Customer dispatches an Action describing the intent

Principles of Redux

image

  • Store holds the state of application The state of whole application is stored in an object within a single store
  • Action describes the changes in the state of the application Cannot directly update the state object that is done by redux only
  • Reducer which carries out the actual state transition based upon the action. Pure reducers which take state and action and returns a new state.

Here is how we can implement above concepts in the banking scenario example :
Action

// Actions Objects to withdraw and deposit money
{ 
  type: 'WITHDRAW_MONEY',
  payload: 1000
}
{ 
  type: 'DEPOSIT_MONEY',
  payload: 500
}

// Action Creator
function withdrawMoney() {
  return {
    type: "WITHDRAW_MONEY",
    payload: 1000,
  };
}
Enter fullscreen mode Exit fullscreen mode

Reducer

const initialState = {
  amount: 5000,
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "WITHDRAW_MONEY":
      return { ...state, amount: state.amount - action.payload };
    case "DEPOSIT_MONEY":
      return { ...state, amount: state.amount + action.payload };
    default:
      return state;
  }
};
Enter fullscreen mode Exit fullscreen mode

Store

const redux = require("redux");
const createStore = redux.createStore;
const store = createStore(reducer);

// access to State
console.log("Initial State", store.getState());

//register listeners via subscribe(listener)
const unsubscribe = store.subscribe(() =>
  console.log("Update State :", store.getState())
);

//state update via dispatch(action)
store.dispatch(withdrawMoney());

//handles unregistering of listeners by function returned by subscriber
unsubscribe();
Enter fullscreen mode Exit fullscreen mode

Going back to the Bank analogy, our bank is expanding and opening current accounts for businesses. It would be difficult to manage retail and business customers from single window as both types of customers have different types of need. So to manage all customers efficiently , bank opens a new window called 'Current Accounts' ( a new Reducer in Redux terms)

const initialState = { 
amount: 10000
}
const currentAccountsReducer = (state=initialState , action) => {
 switch (action.type) {
    case "WITHDRAW_MONEY_CURRENT":
      return { ...state, amount: state.amount - action.payload };
    case "DEPOSIT_MONEY_CURRENT":
      return { ...state, amount: state.amount + action.payload };
    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we have to combine the two reducers to create the store (as it can be only one for entire application).In Bank's analogy this can be kind of token vending machine which gives the customer a token for saving / current account facilities.

const combineReducers = redux.combineReducers;
const createStore = redux.createStore;

const rootReducer = combineReducers({
  savings: savingAccountsReducer,
  current: currentAccountsReducer,
});

const store = createStore(combineReducers)

Enter fullscreen mode Exit fullscreen mode

Whenever an action is dispatched, it goes to both the reducers but only one acts on it , other one ignores.

Middleware
It is the how we can extend Redux with custom functionality. It gives us a point to hook our functionality after action is dispatched and before it reaches the reducer.
One of commonly used middleware is redux logger

const reduxLogger = require("redux-logger");
const logger = reduxLogger.createLogger();

const applyMiddleware = redux.applyMiddleware;
const store = createStore(combineReducers, applyMiddleware(logger))
Enter fullscreen mode Exit fullscreen mode

👇 Here is how we get the state transition in Redux
image

Async Actions

Up till now we have seen synchronous actions ~ as soon as action is dispatched , reducers update the state immediately but in a real world scenario we have to make async API calls to fetch data from endpoint.

Let's see how to fetch data from API and store in a Redux store.

Firstly let's figure out the initial State of Application

const initialState = {
  loading: false,
  error: "",
  data: [],
};

Enter fullscreen mode Exit fullscreen mode

Since dispatch method needs to be called asynchronously so we would need a middleware called 'redux-thunk' which will handle the function returned from our action creator.

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
Enter fullscreen mode Exit fullscreen mode

👇 CodeSandbox to practice above concepts :


In order to understand how to use Redux with React , you can read this post

Discussion (5)

Collapse
zyabxwcd profile image
Akash

the bank analogy fits in perfectly. that was amazing. allow me thy lord to use this whenever i explain redux to someone :)

Collapse
lowlifearcade profile image
Sonny Brown

Thanks for this. The async portion helps a lot. I'd like to hear you talk about it more, though.

Collapse
bhupendra1011 profile image
bhupendra Author

Thank you, I will add more example on handling async action creators in upcoming post : Understannding Reduc with React.

Collapse
bhupendra1011 profile image
bhupendra Author

Here is another blog : dev.to/bhupendra1011/understanding...

Collapse
zohaib546 profile image
Zohaib Ashraf

Thankyou it helps alot i request to share some example regarding redux thunk and redux api calls using middleware