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 :
.
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
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 :
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
- 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,
};
}
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;
}
};
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();
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;
}
}
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)
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))
๐ Here is how we get the state transition in Redux
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: [],
};
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)
);
๐ CodeSandbox to practice above concepts :
In order to understand how to use Redux with React , you can read this post
Top comments (5)
the bank analogy fits in perfectly. that was amazing. allow me thy lord to use this whenever i explain redux to someone :)
Thanks for this. The async portion helps a lot. I'd like to hear you talk about it more, though.
Thank you, I will add more example on handling async action creators in upcoming post : Understannding Reduc with React.
Here is another blog : dev.to/bhupendra1011/understanding...
Thankyou it helps alot i request to share some example regarding redux thunk and redux api calls using middleware