Day 11 - 20
Tags: javascript, react, 100daysofcode
Published: 2022-02-23 18:01:10

## Day 11: Redux
Today I read about redux, some core concepts and when it is necessary to use. I shall create a small project for day 12 and 13 to explain the concepts that I have learnt.

---


## Day 12: Redux (Basics)

Today I read the redux documentation and followed along with the tutorial provided. I will try to summarize all I learnt in two parts as it took two days to read through the documentation. I will then attempt to create a small project to practice what I learnt.

So what is redux? It is basically a library for managing application state. It serves as a centralized store for state that needs to be used by the entire application with certain rules that govern how state should be updated.

What makes redux different from Context api (another React state management feature covered in day 1 to 10) is that it has tooling that makes it easier when you have many state types in large applications, it makes it easier when working in teams because of its clear rules and has state slices to prevent a bloated store file, state slices help manage applications with multiple states.

> Note: Using redux means writing more code and having to learn more, hence it does not need to be used for all applications. One should take the time to think about their application and the best tools to use.

<u>Redux Terminology</u>

**Actions**

This is a JavaScript object that defines something that happens in the application. It looks similar to the actions dispatched in context api

   ```javascript
   // action
   const addUserAction = {
     type: "users/userAdded",
     payload: { username: "John", email: "john@example.com" },
   };

   // action creator
   const addUser = (data) => {
     return {
       type: "users/userAdded",
       payload: data,
     };
   };
   ```
Redux has action creators that creates and returns an action object, this prevents us from writing action objects by hand every time.

**Reducers**

A reducer is a function that receives the current `state` of the application and an `action` object, decides whether to update the state and returns the new state.

Reducers have rules that must be followed, some include not including operations that cause side effects like asynchronous logic, state must remain immutable and should only calculate the new state based on `state` and `action` arguments. These rules will be seen in action in future examples.

   ```javascript
   const counterReducer = (state = { value: 0 }, action) => {
     switch (action.type) {
       case "counter/increment":
         return {
           // state should be immutable
           ...state,
           value: state.value + 1,
         };

       default:
         break;
     }
   };
   ```

**Store**

The entire applications state lives in an object called the store. Redux store accepts a reducer function as its arguments

   ```javascript
   import { configureStore } from "@reduxjs/toolkit";

   const store = configureStore({ reducer: counterReducer });
   ```

**Dispatch**

Dispatch is a function in redux that is used to update the state, it receives an action object as its arguments or action creators to trigger a specific state update.

   ```javascript
   // dispatch an action
   store.dispatch({
     type: "users/userAdded",
     payload: { username: "John", email: "john@example.com" },
   });

   // dispatch an action creator
   store.dispatch(addUser());
   ```

**Selector**

These are functions that extract specific pieces of information from a store. They are mostly used in the view part of the application. Multiple selectors can be used if you have many state slices.

   ```javascript
   const selectCounterValue = (state) => state.value;

   const currentValue = selectCounterValue(store.getState());
   ```

---


## Day 13 & 14: Redux Basics (Practice project)
To practice the concepts learnt in day 12, I will be refactoring the to-do list application made in day 1 that used the context api to use redux and redux tool kit.

The main action types in the to-do list will be adding a task, deleting a task, editing a task and toggling the state of a task as complete and incomplete. The original source code (using context api) is linked in day 1 of this challenge with the live demo.

To add Redux to the to-do list, I first created a store with Redux's `configureStore` function that takes in reducer functions as its parameter and nested the entire App component with Provider from react-redux, with the store as a prop.

```javascript
import { configureStore } from "@reduxjs/toolkit";
import tasksReducer from "../tasks/tasksSlice";

export default configureStore({
  reducer: {
    tasks: tasksReducer,
  },
});
```

```javascript
import store from "../src/app/store";
import { Provider } from "react-redux";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
```
Next I created a tasksSlice file with the `createSlice` function, this allows you to create a state slice making large state more managable. `createSlice` accepts an initial state, an object full of reducer functions and a slice name. It creates action creators and action types that correspond to the reducers state.

```javascript
import { createSlice } from "@reduxjs/toolkit";

const initialState = [];

export const taskSlice = createSlice({
  name: "tasks",
  initialState,
  reducers: {
    addTask(state, action) {
      state.push(action.payload);
    },
    deleteTask(state, action) {
      const { id } = action.payload;
      console.log(id);
      return state.filter((task) => task.id !== id);
    },
   // ... more actions available in source code provided
  }
});

export const { addTask, deleteTask, editTask, toggleComplete } =
  taskSlice.actions;

export default taskSlice.reducer;


```

Finally, to access the actions in the views, we use `useDispatch` to call the action creators and pass in payloads. `useSelector` is also used to read current state.

```javascript
import { useSelector } from "react-redux";

// Get all tasks
const tasks = useSelector((state) => state.tasks);
```

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

 const dispatch = useDispatch();

// add task on form submit by calling add task with a payload of id, name and completed
   dispatch(
      addTask({
        id: nanoid(),
        name: newTask,
        completed: false,
      })
    );

```

This is a summary of what I did, the source code can be found [here](https://github.com/sianwa11/My-Todo-app-redux)

---

## Day 15: Asynchronous code in Redux

To demonstrate how to handle async code in redux, I will use the starwars api to fetch a list of films. Below is my redux store with an initial state holding an empty array of films and a loading state to show the state of requests.

```javascript
import { createSlice } from "@reduxjs/toolkit";

export const LOADING_STATE = {
  WAITING: "waiting",
  REQUESTED: "requested",
  ERROR: "error",
  DONE: "done",
};

const initialState = { film: [], status: LOADING_STATE.WAITING };

export const movieSlice = createSlice({
  initialState,
  name: "movies",
  reducers: {
    uploadMovies(state, action) {
      state.film.push(action.payload);
    },
    loadingState(state, action) {
      state.status = action.payload;
    },
  },
});

export const { uploadMovies, loadingState} = movieSlice.actions;

export default movieSlice.reducer;
```

> NOTE: One of the rules of reducers states that they must not do any asynchronous logic or other "side effects".

In the component, a useEffect hook can be used to dispatch the actions and fetch data from the api.

```javascript
  useEffect(() => {
    dispatch(loadingState(LOADING_STATE.REQUESTED));
    fetch("https://swapi.dev/api/films")
      .then((res) => res.json())
      .then((data) => {
        data.results.forEach((el) => {
          dispatch(uploadMovies(el));
        });
        dispatch(loadingState(LOADING_STATE.DONE));
      })
      .catch((err) => dispatch(LOADING_STATE.ERROR));
  }, [dispatch]);
```
This method works alright but has some drawbacks, it puts too much logic in the component, it is not reusable as this code has to be written in multiple controllers or you might have to call the component every time.

This can be solved using redux middleware.

---


## Day 16: Redux Middleware

For simple applications, the above approach in day 15 would work but when apps get larger you may have difficulties with that approach, for example you may have to repeat certain chunks of code just to carry out the same functionality.

Redux middleware works by first handling an event, like a user click or page reload, an object or function is then dispatched, once dispatched, the value looks for a middleware to make an async call to. Finally when the async call completes, a real action object is dispatched. A better explanation can be found [here](https://redux.js.org/tutorials/fundamentals/part-6-async-logic#redux-async-data-flow), I probably butchered it 😬😂.

Anyway, thunk middlweare allows us to write functions in our reducers that get `dispatch` and `getState` as arguments
> A thunk is a piece of code that does some delayed work. [Link](https://daveceddia.com/what-is-a-thunk/)

Since I used the official redux toolkit package, I did not have to configure the store to add thunkMiddleware. In a different scenario, you have to install `redux-thunk` and enable it in the store as shown below.

```javascript

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/index'

const store = createStore(rootReducer, applyMiddleware(thunk))

```

All I did was add a thunk function in my reducer that now fetches all the movies. This is in the `movie-slice.js` file.

```javascript
export const fetchMovies = () => {
  return (dispatch, getState) => {
    dispatch(loadingState(LOADING_STATE.REQUESTED));
    return fetch("https://swapi.dev/api/films")
      .then((res) => res.json())
      .then((data) => {
        data.results.forEach((el) => {
          dispatch(uploadMovies(el));
        });
        dispatch(loadingState(LOADING_STATE.DONE));
      })
      .catch((err) => dispatch(LOADING_STATE.ERROR));
  };
};

```

Now my component is much more lean as I can now dispatch the `fetchMovies` function in a `useEffect` hook.

```javascript

import {fetchMovies} from "./movies/movie-slice";

  useEffect(() => {
    dispatch(fetchMovies());
  }, [dispatch]);

```

This approach makes fetching movies reusable and separates concerns which can be really beneficial in large projects. I probably did not explain the concept too well and went on rambling but this is how I understood it, I shall do another practice project to make the concept stick. The code can be found in this [branch](https://github.com/sianwa11/redux-async/tree/redux-middleware)

---


## Day 17 to 19: Shopping cart in react-redux

I have been quite busy with a job and commuting, but I will try to push this small project soon and continue to day 20.


UPDATE
I finally managed to finish the shopping cart, here is the [link](https://github.com/sianwa11/Redux-shopping-cart) to the source code.

## Day 20: What I learnt

Day 11 to 20 of this challenge were the hardest for me because I lost motivation on day 19, It took me 2 months to complete the shopping cart project. This was not because of its complexity but because of a little bit of laziness combined with the daily struggles of working a 9 to 5 and commuting.

This is what I have learnt from day 11 to 20

* How to use redux 😁😀
* Showing up is better than not doing anything at all.
* The final product doesn't have to be perfect (This is just a coding and learning challenge)
* One loses motivation but you should never give up.