Understanding Redux without React
Tags: react, javascript, webdev
Published: 2021-10-08 15:01:37

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y07ruqklahnzjnl123ou.png).
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](https://redux.js.org/),  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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxbz35ytkgzh1jtyjmp7.png) 
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](https://blog.isquaredsoftware.com/2021/01/context-redux-differences/#what-is-react-context) on it.

Now lets figure out how Redux can simply above state management process :
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gyx6x67xv6pf2ys97ihd.png)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/deqb4o8l6lz9ajgqm8c9.png)
 
* 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**
```js
// 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**
```js
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**
```js
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)

```js
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.

```js
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](https://www.npmjs.com/package/redux-logger)

 ```js
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
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x341nhu1xvpb85a2vfrl.png)

#### 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
```js
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.
```js
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
```  


👇 CodeSandbox to practice above concepts : 
{% codesandbox redux-without-react-d2gt0 %}

--- 
In order to understand how to use Redux with React , you can read [this](https://dev.to/bhupendra1011/understanding-redux-with-react-27li) post