Redux Data Flow and React Component Life Cycle
Tags: react, redux, hooks
Published: 2020-01-26 23:01:10

<blockquote>
Almost everyone who wants to learn Redux had seen this image before. It's pretty straight forward for me right now, but it's hard to understand when I first learned Redux. 
To have a better understanding of the data flow in Redux. In this article, I will try to explain how Redux works with React. And also try to implement Redux through React hooks.
</blockquote>

![redux-flow](https://i.imgur.com/riadAin.gif)

## First, let start with Redux.   
Redux is a state management system. Therefore, we will need:
1. a place to save the state
2. a method to get the state
3. a method to change the state  

And this is what we do when using Redux:
1.`store` is the place we save the state
```js
import { createStore } from "redux";
import { reducer } from "./reduxModule";

const store = createStore(reducer);
```

2.`getState` is the method to get the state
```js
const state = store.getState();
```

3.`action` & `reducer` is the method to change the mapStateToProps
```js
const INCREMENT = "redux/increment";
const initialState = {
  counter: 0,
};

export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT:
      return {
        counter: state.counter + action.amount
      };
    default:
      return state;
  }
};

export const incrementAction = (amount = 1) => {
  return {
    type: INCREMENT,
    amount,
  };
};
```

The part we need to explain more will be `action` and `reducer`.
Redux update the state through `action` and `reducer`. The `action` tell `reducer` what does it want to do. Then the `reducer` updates the state base on the type and additional data provided by `action`.

### Why use `action` and `reducer`?
I had discussed with lots of people why they are using Redux in their projects. Almost every time the answer will be - "easy to share props between components and prevent [prop-drilling](https://kentcdodds.com/blog/prop-drilling)". I guess this is because back to the time we don't have stable `context API`, using Redux to share props seems to be a reasonable option. But in my opinion, it is not the core concept of Redux.
Using `action` and `reducer` to update the state can make it easier to control. The state can only be changed base on the actions we have defined. And all the logic about how the state should be changed is in the `reducer`. This can makes it easier to maintain.
The idea is like `finite-state machine`. If we want to add more state, 
simply declare another action and add the logic into the reducer.
If you're interested to know more about `state machines`. You can check [this post](https://kentcdodds.com/blog/implementing-a-simple-state-machine-library-in-javascript) written by Kent C. Dodds.

Now, we can visualize the Redux like this.
1. During the initial phase, the reducer received the initial state and return it. So we will get the initial state  ({counter: 0}) in getState.
![redux-init](https://i.imgur.com/HdRPtoN.png)
2. During the update phase, we send an increment action (in redux, we call this `dispatch`) to the reducer, through the switch statement which we defined in the reducer, it will returns a new state ({counter: 0}).
![redux-update](https://i.imgur.com/NOdfZkS.png)


## Next, let's apply in React
When we want to implement Redux in the React, we also need three things:
1. save store state in React
2. get the state in React component
3. dispatch action in React component

For item 1, `react-redux` have a component called `Provider` that can help us do this.
```js
import { createStore } from "redux";
import { Provider } from "react-redux";

const store = createStore(reducer);

return (
  <Provider store={store}>
    <Container />
  </Provider>
)
```

For item 2 & 3, `react-redux` provide another HOC call `connect`. It will turn the state and action into component props. So we will be able to use it in our React component.
```js
import { connect } from "react-redux";
import { incrementAction } from "./reduxModule";

const mapStateToProps = state => ({ counter: state.counter });
const mapDispatchToProps = { incrementAction };
export default connect(mapStateToProps, mapDispatchToProps)(Comp);
```

Now, our component is able to receive the state and dispatch action. Therefore, it's easy to finish our component like this.
```js
import React from "react";

export default function Comp({ counter, incrementAction }) {
  function handleIncreaseOne() {
    incrementAction(1);
  }
  function handleIncreaseTen() {
    incrementAction(10);
  }
  return (
    <div>
      <span>{counter}</span>
      <div>
        <button onClick={handleIncreaseOne}>+1</button>
        <button onClick={handleIncreaseTen}>+10</button>
      </div>
    </div>
  );
}
```
Here is all the code for you to reference: https://github.com/oahehc/react-redux-example/tree/basic

After integrating Redux into React, the visualization should look like this.  
![react-redux-init](https://i.imgur.com/LNpmQzn.png)
![react-redux-update](https://i.imgur.com/bAJNw3d.png)


## Implement Redux through React hooks
Now we know how Redux helps us manage the state, so we can try to apply the same idea through React hooks.
(* This is just an example to demo the basic idea about Redux, please DON'T use it to replace `Redux` and `React-Redux` in your project. If you want to know more detail about Redux, you can check [this tutorial](https://egghead.io/courses/getting-started-with-redux) create by Dan Abramov)  
Just like what we did before, we can split into three items.
1. a place to save the state -> `context API`
2. a method to get the state in React component -> `useContext`
3. a method to change the state in React component -> `useContext` & `useReducer`

```js
// @ReduxModule.js : reducer and action
const INCREMENT = "redux/increment";

export function reducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return state + action.amount;
    default:
      return state;
  }
}

export function incrementActionCreator(dispatch) {
  return amount => {
    dispatch({
      type: INCREMENT,
      amount
    });
  };
}
```

```js
// @Provider.js : apply context API to save the state
import React, { useReducer } from "react";
import { reducer, incrementActionCreator } from "./ReduxModule";

export const ReduxContext = React.createContext();
const initialState = 0;
function ReduxProvider({ children }) {
  const [counter, dispatch] = useReducer(reducer, initialState);

  return (
    <ReduxContext.Provider
      value={{ counter, incrementAction: incrementActionCreator(dispatch) }}
    >
      {children}
    </ReduxContext.Provider>
  );
}

export default ReduxProvider;
```

```js
// @Comp.js : apply useContext to get state and action from Context
import React, { useContext } from "react";
import { ReduxContext } from "./Provider";

export default function Comp() {
  const { counter, incrementAction } = useContext(ReduxContext);

  function handleIncreaseOne() {
    incrementAction(1);
  }
  function handleIncreaseTen() {
    incrementAction(10);
  }
  return (
    <div>
      <span>{counter}</span>
      <div>
        <button onClick={handleIncreaseOne}>+1</button>
        <button onClick={handleIncreaseTen}>+10</button>
      </div>
    </div>
  );
}

```
Reference: https://github.com/oahehc/react-redux-example/tree/custom-redux


When we implement Redux through React hooks, we use `useContext` and `useReducer`. This will bring up the core concept of Redux:
1. useContext : sharing state with multiple components
2. useReducer : handling state by the state machine

---

## Conclusion
Thanks for the reading. I hope this article will make Redux be easier to understand. If you have any question or feedback, please feel free to leave your comment.

--

## Reference
- [Redux](https://redux.js.org/)
- [React-Redux](https://github.com/reduxjs/react-redux)
- [prop-drilling](https://kentcdodds.com/blog/prop-drilling)
- [implementing-a-simple-state-machine-library-in-javascript](https://kentcdodds.com/blog/implementing-a-simple-state-machine-library-in-javascript)
- [getting-started-with-redux](https://egghead.io/courses/getting-started-with-redux)
- [context](https://reactjs.org/docs/context.html)
- [useContext](https://reactjs.org/docs/hooks-reference.html#usecontext)
- [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer)