# Redux and React

# Intro

Recently, I completed my build of a full-stack application using React on the front end and rails on the backend. This application had the most components out of all of my projects....21 (and counting). In my past applications, I used React state and props to handle `state`. In these applications, I made sure to add state in the appropriate parent component. I passed it for miles, through props, to the smallest child component. Then, I realized I needed to pass objects from the child component, back to the parent, so off I would go creating a callback function and passing it down the component tree all over again. This process became old, and I was thankful to find Redux (a global state management library) to avoid this endless process. I am far from an expert, but I would like to relay how I used redux in hopes it might help you with your next application.

# What does Redux allow you to do?

Redux allows the storing of state in a "store." Unlike React state, which is only accessible to children components by way of passing props from their parent components, the store is accessible by any component, at any time. Every component can update `state`. Greatest of all, Redux eliminates the need to remember which components `state` was passed through since it is always available to each component.

Redux does not have to eliminate all props, or local `state`, but it certainly makes global state much easier to handle.

# Getting Started:

### Install Redux

After setting up a react application, we will need to install redux and react-redux. We can do this with npm by using the following command: `$ npm install redux react-redux`.

### Install Middleware Thunk

[Thunk middleware for Redux](https://github.com/reduxjs/redux-thunk) allows us to write, "functions with logic inside that can interact with a Redux store's `dispatch` and `getState` methods." This will help us out in our process. To install this with npm, you can use the following command `$ npm install redux-thunk`.

### Set Up

In my react app, I always add a `.src` file. This file contains all my components, and it is the perfect place to build out our redux items. In the `.src` file, we first need to create two folders. To keep these straight, title the first folder `reducers` and the second `actions`.

## Reducers Folder

In order to have a physical store (like Walmart), you must have products inside for customers to purchase. In Redux, reducers are what will make up our store. They are the items that will contain and manipulate our state so we can view it on the front end. They give us the ability to move complicated functions from our components to one place where we can handle all requests.

### Set Up a Reducer

In the `reducers` folder create a file. It is easiest to name the file with the title of your state, followed by the word "Reducer." This file will be a `.js` file. In my case, I am going to create `state` for a user who has logged into my react app. I titled my file `userReducer.js`.

In this file, we are going to set up a function to return `state` based on what our component calls for. I will explain this in a little more detail shortly, but let me start by showing you what my a basic outline looks like:

```javascript
const initialState = null

const userReducer = (state=initialState, action) => {
  switch(action.type) {
    //If there are no other cases, we will just return state which is curently null. 
    default:
      return state;
  }

}

export default userReducer;
```

I know this might look crazy, but hang in there. Let me go over some basics. This reducer takes in an `action` that has a `type` and a `payload`. We will form our action later, but currently, you can see `action` is the second item our function takes in. The first is `state`. Just like when we use `useState` to set a default state in React components, we can set a default state (like initialState in the example above) and assign it to our state. In the case above, we have set our reducer to always return null if we do not add any other cases to it.

The switch statement above will return a `case` based on the `action.type` we pass to it. So, let's add some case statements to our switch to help clarify what we would like the reducer to return:

```javascript
const initialState = null

const userReducer = (state=initialState, action) => {
  switch(action.type) {
    //If a user signs in, we want to return the user as state. 
    case "ADD_USER":
      return [action.payload]
    //If a user signs out, we want to delete the user information from state, and return our initial state of null. 
    case "DELETE_USER":
      state = initialState;
      return state
    default:
      return state;
  }
}

export default userReducer;
```

In our reducer, we now have a case statement allowing us to add and delete a user. As you might notice, we can use simple JSX and javascript methods to change state based on what we are doing in our component. The `payload` (`action.payload`), which is coming through our action, is the data returned from our fetch request in the component.

Now that we have a simple reducer, let's set up an action so we can pass objects to our state. Make sure to remember the case statements declared in the reducer, so we can use them in the action. In the example above, we will remember `ADD_USER` and `DELETE_USER`.

## Actions

Actions are what allow us to connect our reducer to the component. They are what we create to pass data to `state` from a component.

### Setting Up an Action

Next, we need to create a file in the actions folder. It is simple to title this file with the title of the state we are trying to manipulate. This file will be a `.js` file also. For example, I named my action folder `user.js`.

In this file, we need to export functions for each of the cases we have in our reducers folder. This will connect the reducer with our component and allow us to update state in the reducer. It might make more sense to describe this as the setState function we use in a component. Before I explain further, let me show you what this looks like:

```javascript
export const addUser = (user) => {
  return {
    //Our type must match the case statement from the reducer file. 
    type: "ADD_USER",
    //The payload is passed to this function by our component calling this function. 
    payload: user
  }
}

export const deleteUser = (user) => {
  return {
    //Our type must match the case statement from the reducer file.
    type: "DELETE_USER",
    payload: user
  }
}
```

In the action above, you can see we have an `action type` defined for each case in the reducer. For example, in the addUser function, we are sending the `ADD_USER` case a payload of `user`. `user` is the data we are sending from our React component, and we will see this in action in just a second. In order to pass `user` to our state, we will import the addUser function to the component, and send (or dispatch) our user data to the reducer where `state` is held.

Now that we have these folders set up, let's connect our state to the front end.

## Set Up an Index.js File

Your application likely already has an `index.js` file in the `.src` folder. We want to create a second one that is different from the first. You can create this file in the reducer folder and title it `index.js`. The reason we need to create this folder is to combine all of our reducers into the store. Without this folder, you can only have one reducer in the store, and likely this will not work for most applications that need to maintain state for multiple areas of the application.

In the `index.js` folder, we need to start by importing `{ combineReduces } from 'redux'`. After, we need to import each of our reducers. I am going to add more reducers to demonstrate this idea:

```javascript
import { combineReducers } from "redux";
import userReducer from "./userReducer";
import incidentReducer from "./incidentReducer";
import personnelReducer from "./personnelReducer";
import resourceReducer from "./resourceReducer";
```

Next, we need to combine all the reducers like so:

```javascript
import { combineReducers } from "redux";
import userReducer from "./userReducer";
import incidentReducer from "./incidentReducer";
import personnelReducer from "./personnelReducer";
import resourceReducer from "./resourceReducer";

export default combineReducers({
  user: userReducer, //store.user when using the selector
  incident: incidentReducer, //store.incident
  personnel: personnelReducer, //store.personnel
  resources: resourceReducer //store.resources 
})
```

That's it for this folder. Make sure to include all your reducers so you can access them on the front end!

## Configure the True Index.js

Now, we need to do some configuring inside the `index.js` file contained in the `.src` folder. (Different from the one we just created) This would be your normal `index.js` file.

```javascript
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux'; //!!!!createStore is no longer the recommended way to handle state. A strikethrough will strike through this, but it will still work. 
import { composeWithDevTools } from '@redux-devtools/extension'; // We can use a chrome extension to provide redux dev tools
import thunk from 'redux-thunk'; //Thunk middleware
import rootReducer from './reducers'; //This is the combination of reducers we created in the other index.js folder
```

Once we import the items described above we can implement them by creating a variable for the `store`, and wrapping our app component in the `<Provider>`. Lastly, we need to pass our `store` variable as a prop to the provider.

This will look something like this:

```javascript
import React from 'react';
import { composeWithDevTools } from '@redux-devtools/extension';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk';
import 'materialize-css/dist/css/materialize.min.css';
import { BrowserRouter } from 'react-router-dom';
import ReactDOM from 'react-dom/client';
import App from './components/App';
import reportWebVitals from './reportWebVitals';

//Creating a variable for the store
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={ store }> 
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

reportWebVitals();
```

## Connect With a Component

This has been a lot of work, but we are super close, so hang in there. Last, but not least, we need to connect our `state` with our components. We will need two more items to do this.

### Dispatch

Dispatch is how we send data through the `action` to the `reducer` in order to update `state`. Always remember, we `dispatch` data to the `store`. We `select` state (more on this in a second) to retrieve state.

First, find a component you would like to dispatch data from. In this component:

```javascript
import { useDispatch } from 'react-redux';
```

Now set `useDispatch` to a variable:

```javascript
const dispatch = useDispatch();
```

Lastly, you will need to import the function you set up in the reducer for the task you would like to complete. In my example, I wanted to `fetch` a user's information if they were currently logged in, and assign their information to the `user` state. I first import the `addUser` action we set up earlier, then dispatch the `user` data to the reducer through this function. I know this might be a bit confusing, but it looks like this:

```javascript
import { useDispatch } from 'react-redux';
import { addUser } from "../actions/user";

function App() {
  const dispatch = useDispatch();

  useEffect(() => {
    fetch('/me').then((r) => {
      if(r.ok){
        r.json().then(user => dispatch(addUser(user)))//I am dispatching the addUser action to the reducer where the reducer will update state with the users information. 
      }
    });
  }, []);

export default App;
```

To delete the user, I can simply `dispatch(deleteUser(user))`to the reducer, which will reset my state.

### Select

Now that we have updated our state, we need to access it. We will do this with a selector. The setup process is very similar to setting up dispatch. You can access `state` in any component by following these steps. `State` can still be passed down to children props through normal props. For instance, if you have nested data, you may want to use `useSelect`to grab `state` and `.map` nested objects to a different component.

To get state, you will first need to import useSelect into your component:

```javascript
import { useSelect } from 'react-redux';
```

Then, we can assign a variable to select the `state` we would like to retrieve. Remember, if we have multiple reducers, we need to grab `state` from the appropriate reducer by using `store.ourStateReducer`. This looks like this:

```javascript
const user = useSelector((store) => (store.user)); //Returns our user state.
```

Now, we are able to use the `user` information to set up our app however we might like. Altogether, select and dispatch might look like this:

```javascript
import { useDispatch, useSelector } from 'react-redux';
import { addUser } from "../actions/user";

function App() {
  const dispatch = useDispatch();
  const user = useSelector((store) => (store.user));

  useEffect(() => {
    fetch('/me').then((r) => {
      if(r.ok){
        r.json().then(user => dispatch(addUser(user)))
      }
    });
  }, []);

  return (
    <>
      <div>
        <Navbar />
      </div>
      <div className="container">
        {user ? (
          <Usercard props={user}/>
        ):(
          <SignIn />
        )}
      </div>
    </>
  );
}


export default App;
```

# Conclusion

Redux makes handling state much easier. Initially, it can be a little challenging to grasp, but after discovering the flow of data, Redux will become a simple tool of great help to you. Never forget, you can still always handle simple `state` inside a component, but Redux can handle the state you need multiple components to have access to. I have created a short list of all the steps above should it be helpful. I do not claim to be an expert, but hopefully this will get you started.

## Review of the Steps:

1. Install Redux - `$ npm install redux react-redux`
    
2. Install Thunk - `$ npm install redux-thunk`
    
3. Create reducer and action folders in the .src folder.
    
4. Set up the reducer:
    
    1. Create a default state.
        
    2. Create a `case` to update `state` in the way you would like.
        
5. Set up the action:
    
    1. Assign the type to the `case` in the reducer.
        
    2. Assign the payload to the payload you will be passing the reducer.
        
6. Create an `index.js` file in the `reducers` folder and set up this file:
    
    1. `import { combineReducers } from "redux";`
        
    2. Import all the reducers you have created to this folder.
        
    3. Combine them together.
        
7. Configure the normal `index.js` file in `.src` to work with Redux:
    
    1. Import the appropriate tools from redux and thunk (see above).
        
    2. Create a variable for the store.
        
    3. Wrap the `<App/>` component in the `Provider` component and pass the `store` variable as a prop.
        
8. Depending on if you are dispatching or selecting state:
    
    1. Dispatch (updating state):
        
        1. `import { useDispatch } from 'react-redux';`
            
        2. Assign `useDistpach()` to a variable.
            
        3. Import the function you would like to use from the action.
            
        4. Dispatch the action with the data(payload) to the reducer.
            
    2. Select (accessing state):
        
        1. `import { useSelector } from 'react-redux';`
            
        2. Assign a variable to get the appropriate state.
            
        3. Use the variable as `state` wherever you might like.
            

# Bonus

A cool thing about `actions`, is that you can use them to handle tasks you might repeat in various components. For example, maybe you want various components to fetch data when they render. You can create an action that handles this for you and updates `state` so you do not have to type the fetch multiple times in multiple components.

Here is an example of my set up, and how I used this in the component upon the pages render:

#### Action:

```javascript
export const loadIncidents = () => {
  return (dispatch) => {
  fetch('/incidents')
  .then((r) => r.json())
  .then((incidents) => dispatch({type: "LOAD_INCIDENTS", payload: incidents}))
  }
}
```

#### Reducer:

```javascript
const initialState = []

const incidentReducer = (state=initialState, action) => {
  switch(action.type) {
    case "LOAD_INCIDENTS":
        return action.payload
    default:
      return state;
    }
}

export default incidentReducer;
```

#### Component:

```javascript
import { loadIncidents } from "../actions/incidents";
import { useDispatch } from "react-redux";

const Home = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(loadIncidents());
    dispatch(loadResources())
  }, []);
```
