Redux for beginners
Tags: javascript, redux, webdev, beginners
Published: 2023-04-30 20:08:49

## Introduction

Redux is still regarded as being a notoriously difficult library to work with by entry-level developers despite dominating the frontend world. This article aims to explain the basics of Redux.

## Why developers avoid Redux

The following factors might be reasons why developers tend to avoid Redux:

- Huge Boilerplate code
- Steep Learning Curve

Even with the reasons mentioned above Redux is still one of the most used state management libraries among enterprises, startups and Independent developers. One such enterprise in Robinhood.

## Redux Architecture 

While Redux's boilerplate is one of the primary reasons why it is avoided by developers, it doe have a simple architecture; thereby simplifying the whole process of managing state in applications.

The Redux Architecture is made up of three basic components:

1. Store

2. Reducers

3. Action

### Store

The store is essentially a container that stores the application's global state. There can only be a single store in a Redux application. Data kept in a Redux store cannot be changed. The only way to change the data already stored in a Redux store is to dispatch an action.

Under the hood, a Redux store is just a plain object containing state data that can be accessed at all levels within the application. However, the store has some special methods to control the flow of state data.

The most important methods include:

1. ***getState()***

2. ***dispatch()***

2. ***subscribe()***

The ***getState()*** method returns the state data tree persisted in the store.

The ***dispatch()*** method is used to dispatch an action to the store to change the data stored in the application. It takes an action as an argument.

The ***subscribe()*** method allows us to run a callback function an action is dispatched. This provides a way to get the recent data in the store by calling the ***getState()*** method.

The ***createStore()*** function allows us to create a store by taking a reducer function as an argument.

```javascript
import { createStore } from "redux"

const store = createStore(reducer)
```

###Reducer

The Reducer is a function that contains the logic of how state data is saved in the store. The Reducer function simply takes the current state and the dispatched action as arguments and returns a new state based on the arguments.

The code below shows a basic implementation of a reducer function.

```javascript
const initialState = {value: 0}

const myReducer = (state=initialState, action) => {
  if(action.type === "INCREMENT"){
    return {
      ...state,
      value: state.value + 1
    }
  }
}
```

As you can see, the initial state variable represents the current state in the application and a new state was returned based on the action that was dispatched.

However, a Redux application usually has more than one Reducer, each storing unique data for use in different parts of the application. Luckily redux provides us with the ***combineReducer()*** function.

The ***combineReducer()*** function takes an object whose values are reducing functions and returns a single reducer. This helps in projects with a large codebase where modularisation is needed for easy code maintenance.

```javascript
const combination = combineReducers({
  posts: postReducer,
  counts: countReducer
})
```

The state in each reducer can be easily accessed by using the keys provided in the ***combineReducers*** function.

Since Reducers are pure functions, the following rules must be observed:

- Reducer functions should not contain side effects like asynchronous functions.

- Reducers should not modify the current state directly.

- To modify the current state, reducers should make a copy of the current state and return the modification as a new state.

But One may ask, If Reducers can't run asynchronous functions, then how does one deal with data fetching in a Redux application? This is where middlewares come in.

#### Middlewares

A middleware is a function executed between the period an action is dispatched and before it gets to the reducer. This middleware, in turn, provides an environment to run asynchronous functions and other side effects, particularly data fetching. The resulting data from the side effects function is then passed to the Reducer to complete the data manipulation cycle.

In short, Reducers determine how the state data is changed and middleware intercept actions before they are passed to the Reducers.

### Action

Actions are simply events which trigger a change in State. They sort of define a particular task in an application. For example, suppose a counter application has buttons for incrementing and decrementing a count variable, the task of incrementing and decrementing the count variable could be considered an action in redux.

In Redux, an action is a plain javascript object with two properties: **type** and **payload**.

- The **type** property describes the action to be dispatched.

- The **payload** property allows us to attach some data to the action object so we can access it in the Reducer to save it in the store.

Below is a simple implementation of Redux actions.

```javascript
const action = {
  type: "INCREMENT"
}

const anotherAction = {
  type: "SAVE_TODO",
  payload: "Get Groceries"
}
```

If we consider the second action in the code above we could write a reducer function to access the payload and save it in the store. The implementation can be found below.

```javascript
const initialState = {todos: []}

const anotherReducer = (state=initialState, action) => {
  if (action.type === "SAVE_TODO"){
    return {
      ...state,
      todos: [...state.todos, action.payload]
    } 
  }
}
```

This aspect wouldn't be complete without mentioning action creators.

Action creators are functions that return actions. Action creators allows us to create actions on the fly.

```javascript
const actionCreator = (type, payload) => {
  return {
    type,
    payload
  }
}
```

We can now create actions easily by passing the necessary parameters to the function.

```javascript 
const customAction = actionCreator("DELETE_TODOS", "Buy Groceries")
// returns {type: "DELETE_TODOS", payload: "Buy Groceries"}
```

With the above implementation, we can pass payloads dynamically.

###Stitching it together

At this moment, you should have grasped the basic concepts of Redux. We go further by building a simple counter application in Redux.

The application will have the following:

- An HTML template

- Two actions for incrementing and decrementing

- A reducer function for the actions

- A store for persisting data

We start by creating the UI template. We could decide to use the default value from the store but in this case, I'm just going to write the default value in the HTML.

```html
<h1 id="target">0</h1>

<button id="increment">Increment</button>
<button id="decrement">Decrement</button>
```

We then create the Reducer function.

```javascript
const countReducer = (state={value: 0}, action) => {
  if(action.type === "INCREMENT"){
    return {
      ...state,
      value: state.value+1
    }
  } else if(action.type === "DECREMENT"){
    return {
      ...state,
      value: state.value-1
    }
  } else {
    return state
  }
}
```

As a rule of thumb, you should always return the current state if the action doesn't match in your reducer function.

We then move on to create the store and use the ***subscribe()*** method to update the DOM when actions are dispatched.

```javascript 
const store = createStore(countReducer)

store.subscribe(() => {
 const { count } = store.getState()
 document.querySelector("#target").innerText = count
})
```

Finally, we create the actions and dispatch them when the buttons are clicked.

```javascript
const increaseCount = {type: " INCREMENT"}
const decreaseCount = {type: "DECREMENT"}

document.querySelector("#increment").onclick = () => {
  store.dispatch(increaseCount)
}

document.querySelector("#decrement").onclick = () => {
  store.dispatch(decreaseCount)
}
```

The snippet below shows the complete implementation.

{% codepen https://codepen.io/Captain-Prinz/pen/QWZpazm %}

###Conclusion

Save for its huge boilerplate, Redux can greatly simplify code maintainability, especially for projects with large codebases.

Other concepts will be discussed in subsequent articles.

If you find this article helpful, please leave a comment and suggestions on other web technologies.

Happy Learning!