How to Implement Redux in Your React App

Kenny Quach
10 min readDec 16, 2020

--

I know what you're thinking. You are thinking why do you need to learn redux and why is it so difficult to wrap your head around it. Well, I am here to tell you what is it, why it is essential to know it, and why it isn't as difficult to learn as you may have thought.

The What and Why

Firstly, lets discuss why it is so important to know redux. As you may have already heard, redux is a third party library that manages the state of an application in a predictable manner. Essentially, the state’s actions will always be based on code that you specify beforehand which we will explore ahead. Many applications are using redux, especially those that hold large amounts of data. That being said, not all applications require redux, in fact there are apps that do well without the redux. It all comes down to how much data your app is holding and whether or not you find yourself continuously having to pass down props to irrelevant components. Take the following image for example:

Lets first take a look at the component tree without redux. As you can see, in the above image, each node represents a component. Now, lets say that the purple component needs to get data that is stored at the the component at the very top. We would need to pass that data in the form of props until the data reaches the purple component. This is very troublesome, because you would need to pass that data to the component underneath, which would need to then pass that data to the component below it, so on and so forth. This is a phenomenon called ‘prop drilling’ and you should avoid this. The reason is that over time, your app will get bigger and more complex and you will find that your app is getting slower and more confusing to manage because of all the props that are being passed to one another.

The solution

Instead, wouldn't it be nice if there was a centralized location where we can grab the data whenever and wherever we need to? That is where redux comes in and saves the day. As you can see in the previous illustration, Redux utilizes something called the ‘store’ where the state is stored and where you can always pull the desired data in respect to the component that is trying to access the data. This eliminates the repetitive nature that arises from prop drilling making for a much faster, and efficient application, which in turn, makes your life much easier.

Redux Terms

When I first started learning redux, I came across terms and definitions that made me contemplate life. What the heck are actions? What in the world do you mean by reducers!? During the early days of reading the redux documentation, these were the questions I was asking myself.

I will go over briefly the terms and how I believe you should think of them.

Actions

These dictate what happens to the state. They are plain JavaScript objects that will always have a type property inside of them and may also include a payload, which stores additional info. When we want to change the state, we do so by dispatching an action. Actions generally looks like:

const addTodoAction = {type: ‘ADD TODO’,payload: ‘Buy milk’}

Action Creators

Action creators are functions that creates and returns an action object. They aren't essential to utilize, however, they can come in handy as you dont need to write out your actions by hand every time. Below is an example of an action creator.

const addTodo = text => {return {type: ‘ADD TODO’,payload: text}}

As you can see, the contents of the return object in the action creator is similar to the content of the return object in the action example. The key difference is that action creators are functions, rather than objects , which means you can store these functions and call them more dynamically. In this example you can see that the text is being passed as a parameter. If we wanted to add a new todo, we can do so dynamically by passing the todo as a parameter. On the other hand, if this were only an action, every time you wanted to add a new todo, you would have to do so by returning a new action object:

return {type: ‘ADD TODO’,payload: ‘take out the trash’}

Reducers

Reducers are functions that receives the current state and an action object as the parameters, and returns a new state. Think of reducers as event listeners that handles events based on action types. They can be written either using if else or switch case statements. Here is an example of a typical reducer function using the switch statement:

function reducer(state = initialState, action) {switch (action.type) {case “INCREMENT”:return {count: state.count + 1,};case “DECREMENT”:return {count: state.count — 1,};default:return state;}}

Redux Store

The redux store is where the state of the application lives. The store’s state should never be mutated directly. Instead, it should take in reducers that takes the old state and in return replace it with the new state. You will later see this in action.

Learn By Doing

The best way to learn is by doing and playing around with the library itself. Therefore, I have created a simple and clean counter app that implements redux so that you can get an idea of how redux works. Its so clean, only three files will be used in my example!

Setup

  1. Let us start by installing the required packages.These packages are redux and react-redux. The redux library is the core redux package that we will need to utilize redux while the react-redux package is the library that is going to connect react and redux together. If we were to only install redux package, react would not know what to do with the redux package. Think of the react-redux package as a connector of react and redux.
npm i reduxnpm i react-redux

2. Next we will setup the store. Now, we need to decide where the store should live on our application. A good choice would be to place the store at the top most component on your component tree. That would be the root of the application which we can find in the index.js file. You should find something similar to below by default.

// index.jsimport React from “react”;import ReactDOM from “react-dom”;import App from “./App”;ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,document.getElementById(“root”));

Now, at the top, you should import:

import { createStore } from “redux”; // we need this to create the redux storeimport { Provider } from “react-redux”; // we need this to basically make the store visible to react and vice versaimport { reducer } from "./reducer"; // we will create a reducer file, which contains a reducer function. For now just import it

It is now time to create the store and pass in the reducer that we will create in a bit:

const store = createStore(reducer);

After the store is created, we need to utilize the provider from the react-redux library to let react see the redux store and vice versa. We need to wrap our app component in the Provider tags. Since the App component is the root component on our component tree, all our components in the application will have access to the state. The provider takes an attribute named ‘store’ and we pass it the store that we created above. Now your index file should look like:

import React from “react”;import ReactDOM from “react-dom”;import App from “./App”;import { createStore } from “redux”;import { Provider } from “react-redux”;import { reducer } from “./reducer”;const store = createStore(reducer);ReactDOM.render(<React.StrictMode><Provider store={store}><App /></Provider></React.StrictMode>,document.getElementById(“root”));

Create the reducer

Now lets go ahead and create a reducer.js file in the src folder.
The reducer is a function that accepts two arguments. The first argument is going to be the state and the second argument being the action. For the state, generally we create a default object with a default value. Lets create the initial state now.

const initialState = {count: 0,};

Now, the reducer:

export function reducer(state = initialState, action) {switch (action.type) {case “INCREMENT”:return {count: state.count + 1,};case “DECREMENT”:return {count: state.count — 1,};case “RESET”:return {count: 0,};default:return state;}}

As you can see from the code above, we passed in the state and set it to the initialState object that we created above. The second parameter we passed is an action. Next we implemented a switch case to execute based on the action type that the reducer “listens” to. In our example, the action types are INCREMENT, DECREMENT, AND RESET. If the action type is INCREMENT, we will increment the count by one. If DECREMENT is the action type, we will decrement the count by one. Furthermore, if the action type is RESET, we will reset the count at 0. We also have to return a default case in which case it just returns the state back to us. You always want to have the state returned back to you whether you are using switch case or if else statements. One thing to note is that we never directly set the state. We ALWAYS return a copy of an updated object. Have a look at the return statements in the switch case statements above. There may be case where you want to create multiple reducers, but for this example, I will stick to a single reducer for your sake. With that you are done with the reducer.js file. Your reducer.js file should look like:

const initialState = {count: 0,};
// export your reducer
export function reducer(state = initialState, action) {switch (action.type) {case “INCREMENT”:return {count: state.count + 1,};case “DECREMENT”:return {count: state.count — 1,};case “RESET”:return {count: 0,};default:return state;}}

Next lets work on our App.js file. We will see some tangibility in this file. Your app file should look similar to the following by default:

import logo from ‘./logo.svg’;import ‘./App.css’;function App() {return (<div className=”App”><header className=”App-header”><img src={logo} className=”App-logo” alt=”logo” /><p>Edit <code>src/App.js</code> and save to reload.</p><aclassName=”App-link”href=”https://reactjs.org"target=”_blank”rel=”noopener noreferrer”>Learn React</a></header></div>);}export default App;

First, delete everything in between the opening and closing div tags. Afterwards, you should import ‘connect’ from the react-redux library. At the top of your file, write the following:

import { connect } from “react-redux”;

This is going to give you access to the connect higher order function that will allow you to map the state and dispatch your actions to the component’s props.

Next, we will create a simple view consisting of a decrement button, the count with a static value of 0 that I typed manually, the increment button, and a reset button. Also, bring in the props into your app component by entering it as a parameter. Your file should look like the following as of now:

import “./App.css”;import { connect } from “react-redux”;function App(props) {return (<div className=”App”><button>-</button><span>Count:0</span><button>+</button><button>Reset</button></div>);}export default App;

Map the State to props

It is time to map the state to the props of our component:

const mapStateToProps = (state) => {return {count: state.count,};};

As you can see, we create a function that returns the state object to our components props. This is merely what is going on here.

Map the dispatch to props

Mapping the dispatch to the props is similar to mapping state to props, however this time we are not mapping the state. This time we are mapping the dispatches to the props of our component. The dispatch dispatch functions take the action object as the parameter:

const mapDispatchToProps = (dispatch) => {return {increment: () => dispatch({ type: “INCREMENT” }),decrement: () => dispatch({ type: “DECREMENT” }),reset: () => dispatch({ type: “RESET” }),};};

Wrap your component in the connect higher order function and pass in the mapStateToProps and mapDispatchToProps

export default connect(mapStateToProps, mapDispatchToProps)(App);

The above code makes your state and dispatches visible to your app component. Its connecting the state and dispatches to the props of your component. Lets console log our props to see exactly that in action.

As you can see, we have an object with the count and the dispatches that we just passed into our higher order function.

Access the state and dispatches

Now we can access the state and dispatches through props. Lets use them in our view. We can now attach a corresponding onClick listener to each of the buttons via props. For decrementing the count, we use props.decrement, incrementing the count would be props.increment, resetting the count would be props.reset. Additionally, access the state count dynamically via props.count:

<div className="App"><button onClick={props.decrement}>-</button><span>Count:{props.count}</span><button onClick={props.increment}>+</button><button onClick={props.reset}>Reset</button></div>

Your finished app.js file should look like the following:

import “./App.css”;import { connect } from “react-redux”;function App(props) {console.log(props);return (<div className=”App”><button onClick={props.decrement}>-</button><span>Count:{props.count}</span><button onClick={props.increment}>+</button><button onClick={props.reset}>Reset</button></div>);}const mapStateToProps = (state) => {return {count: state.count,};};const mapDispatchToProps = (dispatch) => {return {increment: () => dispatch({ type: “INCREMENT” }),decrement: () => dispatch({ type: “DECREMENT” }),reset: () => dispatch({ type: “RESET” }),};};export default connect(mapStateToProps, mapDispatchToProps)(App);

Bam! You have just set up redux

Try out the app. Congratulations on setting up and creating a redux counter react app.

--

--

Kenny Quach
Kenny Quach

Written by Kenny Quach

0 Followers

Passionate web developer who is continuously learning

No responses yet