Intermediate Step-by-Step Tutorial Using React, Redux and Redux-Saga: Part 1

Johannes Neumann
7 min readJun 27, 2017

--

Important: This tutorial assumes that you know React and that you know a little bit of Redux. Although I explain Redux briefly, the topic could fill multiple blog posts by itself (and there are quite a lot of blog posts on it). If you know React and went through the redux example, then you’re fine.

If you just want to get started, know React and some Redux, take a quick look at the ‘What are we building’ section, then look at the architecture diagram, and start with part 2 of the tutorial

Hello everyone!

In this series of blog posts I will show how to create an application using React, Redux and Redux-Saga. The goal of this series is to create an app, which is built with scalability in mind. We will start from scratch, create the underlying structure with Redux to manage our application state, and use Redux-Saga to connect to a publicly accessible API (no auth token needed). Finally, we will use a combination of Jest and Enzyme to test our application (including our sagas!). In part 1, I will briefly explain Redux (as noted, this tutorial is not meant as an introduction to Redux), show you exactly what we are building and focus on the underlying application architecture. In part 2 we will start actually coding the app.

Who is this tutorial for?

This tutorial is aimed at developers who already have experience with React and who have an understanding of the general flow of Redux (basically you know a bit about actions / reducers and the store and that’s about it). I won’t be going over much of the React-specific stuff. Additionally, you should be comfortable with ES6. You do not need to know anything about Redux-Saga or Jest / Enzyme (tools used for testing).

What are we building?

We are building an application which displays a list of European countries (first these countries will be hard coded, later we connect to an API) and once we click on a country we get more information about it such as population and its capital city. Additionally, we will be able to filter the list of countries using a client-side live-search. As they say, a picture says more than a thousand words, so here you go:

The application is relatively straightforward, yet it should cover quite a lot of topics. Additionally, there are a ton of ways to extend it. For example, we could add all the countries and filter them by region. There are also performance optimizations that we would have to think about in the real world, such a caching API requests. We’ll discuss all of that at the end of the series. Now that we know what we are building the next step would normally be thinking about the architecture, but before we can do so, we need to understand Redux.

Redux — a brief refresher

Let’s briefly refresh our memory on what Redux is and how it flows. Redux is a way to manage the application’s state and is a variant of the flux architecture. Redux uses a single store, which holds the state of our entire application. The store is changed by dispatching so-called actions. Actions call functions that take the previous state of the store and the action in order to produce the next state of the store. These functions are known as reducers. The important part here is that reducer functions need to be pure. This means that when given an input, the function will always produce the same output, and the function itself does not produce any side effects such as mutating an object. Pure functions are a cornerstone of functional programming, which is core to Redux.

The Redux pattern can be summarized with the following picture (there are many slightly different iterations of the image, just type ‘redux cycle’ into Google images):

Redux cycle

Let’s look at a concrete Redux example using the application we will be building. In our application, a user can search for a country by typing letters into the search field. When a user types a letter an action is dispatched:

// action dispatched for every letter typed into the search fieldexport const changeSearchFieldInput = inputValue => ({
type: types.CHANGE_SEARCH_FIELD_INPUT,
inputValue
});

Once the action is dispatched, the reducer function will use that action and the previous state of the store, to determine the next state:

// reducer updates the searchFieldInput after the
// CHANGE_SEARCH_FIELD_INPUT action was dispatched
const initState = {
searchFieldInput: ''
}
export default function countriesReducer(state = initState, action) {
switch (action.type) {
...
case types.CHANGE_SEARCH_FIELD_INPUT:
return {
...state,
...searchFieldInput: action.inputValue
};
default:
return state;
}
}

Finally the store will be updated with the new state causing the UI to re-render the list of countries based on the filter condition. Here we pass the filtered countries to the child as a prop:

<CountryMasterPage
countries={filterCountries(
this.props.countries,
this.props.searchFieldInput
)
}
...
/>

As I mentioned previously this section is more of a refresher than a proper introduction to Redux. Redux itself is a large topic that is definitely worth exploring and while doing so it’s also worth looking into functional programming. I’ll post some useful links at the end of the tutorial. Now that we know a little bit of Redux we can finally start.

Application Architecture

Before we start coding we should consider how we want to structure our app. The app is split into two sections, the left side of the app which we will call MasterView and the right side which we will call DetailView. Additionally, we want to separate components into two different kind of components, one that deals with data and is connected to the store (we call these Containers) , and other components which only display data and call actions. These components have no knowledge of Redux, and the actions they dispatch, are just normal functions which were passed to them by their parent (more on this later). By separating the components in such a way we have a better understanding of what is going on in our app. This will make testing easier and allow us to reuse components, which are not concerned with data, more easily. Dan Abramov (creator of Redux) defined this concept here.

When we separate the app into Master / Detail, we see that the MasterView consists of a SearchField and a List component, while the DetailView only has a CardComponent. As we are using React the data will flow one-way, from the top to the bottom. Next we should think about what components we need and what their responsibilities are in regards to accessing the store and passing down props.

Let’s start with the MasterView. Because we are using Redux our props will initially come from the store’s initial state. As discussed we need a container component which connects to the store, lets call it MasterViewContainer. The container will be responsible for getting data from the store and passing it down to it’s children. Next we need a component which manages the layout, this will be our MasterViewPage. We call this component page because it structures the entire screen. With this convention we will have a better overview of the app, especially once it becomes larger. The MasterViewPage will receive all props from the container (i.e. it does not know about Redux) and distributes these props accordingly between the SearchField component and the ListView component. Further the list component will consist of many list items which we will call ListItem component. The DetailView is a bit simpler. We will use a DetailViewContainer which has a DetailViewPage as it’s child. Finally that DetailViewPage will have a Card component to display the selected country.

Putting this architecture overview in writing can quickly get a bit confusing, so here is an image demonstrating the components we need, their props and their relationship with the redux store.

Application architecture will be implement in part 1 and part 2 of this tutorial series

A few things to note here. At the very top we see the entry point of the application, called index.js. This file will only make sure the AppContainer is rendered into the correct div element. We have not talked about the AppContainer and AppLayout yet, so let’s do that now. The AppContainer is responsible (for now) to create the store and wrap the the AppLayout in a provider, so that other components can access the store using connect. Its direct child is the AppLayout. Why not put the MasterViewContainer and the DetailViewContainer in as direct children and forego the AppLayout? That is certainly possible, but in the spirit of creating a scalable application we use this extra component. If for example, we wanted to create two different layouts, one for logged in users and one for logged out users, we could create an AnonLayout and let the AppContainer decide which layout to call.

At this point it might be good to point out that most readers wont agree with all the design decisions made, even though the app is small. This is ok and expected. It is important when you make design decisions that you have a solid reasoning for doing so and no solution is perfect. With that being said, we are now ready to start coding. So jump into part 2 of this series and let’s start!

Feedback and any corrections are highly appreciated!

--

--