Wiring Up a Redux Store in React Apps

In this article we will go through the process of setting up a Redux Store inside a React App. Even though the Context API are now available out of the box in React, the use of Redux is still widespread and maintains its charme and advantages. I thought it was a good idea to have an article to use as a reminder of the steps needed to manually put in place a Redux Store in order to start with new React/Redux projects faster!

What you should know to follow

In this tutorial I shall assume you already know about React and its fundamentals (components, state, props) and that you already know what Redux is and how it works. You should also know already what reducers, actions and action creators are. Nevertheless, we will take a few minutes to refresh our memory about what Redux is, and how it works.

Important Note

As of today it is possible to initialize a “redux-ready” React app with tand the Redux-JS template option, in order to make use of the Redux Toolkit package, intended to provide a standardized way to structure a React/Redux project and avoid boilerplate code. However, the purpose of this guide is to show how to manually implement a Redux Store and its middlewares, so we won’t use Redux Toolkit here.

What Redux is and how it works

according to its official website:

Redux is a predictable state container for JavaScript apps.

The basic idea behind Redux, is to have an immutable big object called Redux Store which represents the only source of truth in the whole application. This object can be modified only through some predictable (predefined) actions.

A store is composed by different reducers. A reducer is a function whose purpose is to manipulate a small set of data representing a specific aspect of our application business in a form of an object called state.State can only be modified in a predictable way through some predefined actions. An action is basically an object that by convention has 2 properties:

  • a string that defines its “purpose”, used by the reducer function to detect whether to change the state or not and how to change it.
  • an object containing the data that needs to be used by the reducer function while modifying the state. It is an optional parameter since sometimes no payload is needed.
{type: 'ADD_ITEM', payload: {id: 1, name: 'pencil'}}

These actions need to be dispatched (triggered) by some functions, which we define as action creators. Once the action is dispatched, it gets passed to all the reducers of the state.

Examples of actions creator. Note how payload is not always needed.

The reducers will have some instruction on how to modify their state object according to different action types.What I described so far can be achieved without any particular library. In fact, even inside a React application, we will define our actions, action creators and reducers with plain JS objects and functions.

An example of reducer. Instructions are provided according to the type of action. Note it always return a state.

What we have seen so far can be achieved without any particular library. In fact, even inside a React application, we will define our actions, action creators and reducers with plain JS objects and functions.

It is only when we need to wrap up all our reducers and action creators together that we will make use of the Redux library. More precisely, we will use a few special functions from the library:

  • useful to put together all our reducers into a single object
  • which takes the object created through and returns a Redux Store.
In our reducer folder we may want to create a barrel of all our reducer and combine them with Redux, then we export the combined reducer so to transform it in a store in the main file of our application as we will see later.

The benefit of combining the reducers into a single store, is that every time an action is passed to , it is then passed through all of our reducers. Once all the reducers have returned their state, they are combined again to form the updated Redux Store.

We can summarize the flow with the following schemas:

A Redux Store is created by combining the reducers
The Redux Store is modified by using the Actions flow

Keeping in mind what we have just sais, let’s see how we integrate the Redux pattern inside a React Application.

Redux in React

The first thing I want to point out, is that when we talk about Redux in React we basically talk about the React-Redux library.

It is this library that allows Redux and React to communicate with each other properly and makes it easier for us to read the store data or dispatch our functions.

As stated in the introduction, we are not going to use the ReduxToolkit for this article, so assuming we created our app with and no particular template, we must install the Redux library and the React-Redux library manually:

npm install --save redux react-redux

1- Defining reducer and action creators

Before we actually use any function from the redux or react-redux library we will have to create our action creators and reducers. I usually structure my projects in order to have a and folders where I define all my functions separated by topic and then barrel them into a single file to be exported.

2- Combining reducers

Most importantly, make sure that inside file you combine all your reducers with redux’s function:

We want to export all the reducer combined, in order to transform them into the Redux Store.

Keep in mind that the key you provide inside the argument, will be used as a prop inside the Redux Store.

3 - Creating the State and wiring up the Provider

We must make sure to create a Redux Store out of our combined reducers and provide it throught our application.

To create the store, all we have to do is to import our combined reducers and call the function provided by the Redux library.

To make the store available to all our components, we will make use of the Provider component of the React-Redux library. This component expects a store as a props and it is intended to wrap our entire application, namely, our component!

Once we have wrapped our main component inside the provider, all our nested components will be able to get access to our state data!

Accessing the store

We have said we are now able to reach our state from all the components in our app but we must see how. There are actually 2 different methods to read the data from the store: the connect function and the useSelector hooks.

Option 1: Connect & mapStateToProps functions.

The most traditional way to get access to the store data from one of our components, is to pass the entire component to the function from react-redux.

The connect function will return a copy of the component entirely connected to the store. However, in order for the component to properly read the store data, we must first provide an important argument to the connect function:

mapStateToProps is a function used for selecting the part of the data from the store that the connected component needs. This function should be passed as the first argument to , and will be called every time when the Redux store state changes.

mapStateToProps is called with the entire store as its first and only argument and should return an object where all the keys represent the mapped props from the store, to be consumed in the reducer. Let’s try to make an example:

If we want to read our list of items from our store inside of a MyList component, this is what we would do:

Note how the object returned by mapStateToProps is defining the name of the props the component will use to access the data.

An important aspect is that the connect function can be used for both class and functional components.

Option 2: useSelector (functional components only)

In the last version of React-Redux, hooks are available for us to use inside our functional components.

In order to read data from the Redux Store, we may use the useSelector hook. The useSelector hook is conceptually corresponding to mapStateToProps but it has some differences, the most important being:

  • It can be used only inside functional components.
  • It can return any value, not necessarily an object.
  • It can be declared multiple times inside the component.
  • It is called every time the components re-render but only if its returned value has changed.

Its use is however very similar to mapStateToProps, since its mandatory first argument is a function that receives the entire store, just as in mapStateToProps , with the difference, as already said that it can return any value. Let’s see the same example with useSelector:

Dispatching the actions and modifying the store

Now that we have seen how to read data from our store, let’s focus on how we can perform changes on it, that is, how to dispatch our action creators!

If you have understood how Redux works, it will be clear to you that in order to trigger an action and send it to all the reducer in the store, what we need is to pass an action creator to the function.

But how can we access the dispatch function from a component? Well, here is where the React-Redux magic comes into place and again, we have 2 different ways!

Option 1: Connect & mapDispatchToProps

Very similarly to what we have seen with mapStateToProps, the connect function allows us to map also the actions creators to the component’s props.

The trick is very simple: connect can accept a second parameter called, guess what? mapDispatchToProps.

needs to be an object whose keys will be mapped to a prop inside a component. Each key of this object must be a function that eventually returns an action, that is, an object with (mandatory) and (optional) arguments.

Let’s see a very simple example, extending the previous MyList.js component. We will import our previously declared action creator from its file, and map it to a property inside the component. We will then add a button for each item of the list, and try to call our delete property with the id of the item as its argument:

IMPORTANT NOTE: in some cases we only want to use action creators inside a component, regardless of the rest of the store. In those cases, you should provide as the first argument to connect and as a second argument!

Option 2: useDispatch (functional components only)

An even simpler approach is available to us inside of functional components, thanks to the useDispatch hook.

This hook provides a direct reference to the function, making its use really straightforward.

Of course, you only need to call the hook once inside a single component and then use its reference with different action creators.

Let’s see how our example MyList looks with this approach:

Handling async actions with Redux-Thunk

There we go, my friends! We have our store in place now, but we need to handle a little issue that we may have if we need to consume some API inside our actions creators.

The problem

Remember: action creators are supposed to return a plain object. But when we make use of asynchronous code, we are breaking this rule and Redux is going to show a very big error screen to us:

If we perform an async call inside an action creator, this is what we run into.

The solution

In order to bypass this issue, we will make use of a middleware called Redux Thunk.

What Redux thunk does, is putting itself in the middle every time an action creator is called and performs a check on what is returned; if the return value is an object, it will then call for us.

If the return value is a function, it will prevent redux from breaking and instead will provide a new functions with 2 arguments out of the box:

  • the dispatch function, that we can use to dispatch the action once we performed all our async code or other logics
  • a getReduxStore function, that we can use to inspect the whole content of the store!

Let’s see how to implement this. We can install it with

npm i --save redux-thunk

We can now move to our file and import from redux thunk and from the redux library.

All that remains to wire up Redux-Thunk is to pass as the first argument to and as the second argument to . From now on, all our actions will be handled by the thunk middleware.

But remember: all Redux Thunk does is allow our action creators to return a function and provide that function with the function to be called whenever our async functions are finished. So let’s see a proper way to handle asynchronous tasks inside our action creators:

Passionate Coder. Currently Front End Developer @ CWS Digital Solutions

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store