Build Youtube in React 18: Adding Redux and redux-saga
1.1 Introducing state
Now that we have built out our
Youtube MVP components, we can think about how we get actual videos in there. Otherwise the app would be kinda boring.
Our app will make use of Youtube’s Data API v3, an API that allows us to fetch information on videos, categories, comments and so on.
Now let’s suppose we already fetched data (video categories, video view counts, …) from the Youtube endpoint. How do we store it?
We could store it in the component’s local state, but this will get quite messy because some of the data is shared by multiple components.
Therefore we will use
Redux, one of the most popular state management libraries out there.
1.2 Redux principles recap
If you worked with
React before, chances are you already know
Redux. I will not go into extreme detail how it works, I’ll just revisit some of the basic aspects. Otherwise, we need
100 tutorials to finish the app. If you are not familiar with
Redux, I highly recommend checking out the official documentation. It is very well written and quite straight forward. I also recommend checking out the Redux video course by Dan Abramov on egghead.io.
Redux follows three principles
- The global state of the application is stored in an object tree in a single store
Reduxstate is read only (unidirectional data flow). The state can only be changed by dispatching an action
- The store is updated by pure functions (i.e. functions without side effects). Those functions are called reducers.
For brevity, we cannot go in depth on how
Redux works. Again, please check out the official docs.
2 Setting up a Redux store in React
2.1. Basic setup
We need two additional packages. The first one is
Redux itself and the second library is the binding between
Redux itself is standalone and is not directly tied to
React. That’s why we need a package to glue them together
First things first. let’s create a
store directory inside
src where we will put everything related to
Redux. We will need a directory where we put all of our actions and a directory where we put all of our reducers.
- Create a new directory called
- Inside store, create a
- Add an empty
index.jsfile both inside the
Nice, we now have the basic structure for
Redux set up.
To create our store, we need a reducer. So head over to you
index.js file inside the reducers directory and put the following code there
This reducer does – you guessed it – nothing. But we can see how a reducer is supposed to look. The reducer is a pure function that takes in two parameters: the current state and the action that was dispatched. An action is just a
type property. The
type property’s value should be a unique
string that describes what has happened in the application.
Depending on the action’s type, the reducer is supposed to calculate the next state based on the current state. Bear in mind that the
Redux state is immutable, so our reducer may not change the current state, but must always return a new object if something was changed.
Right now, our reducer does not do anything because we always return the state we currently have. The initial state is set to an empty object.
2.2. Configuring the redux store – adding middleware
To create a
Redux store, we need a reducer. We already have that. Nice.
The actions dispatched via
Redux are synchronous. However, in order to reach out to the network, we need the ability to dispatch actions asynchronously. One of the most popular ways that allows us to do that is redux-thunk. Redux-thunk is kinda nice, but will not be sufficient for our purposes.
Believe me, I know that because I first built this application using
redux-thunk and it got quite messy. To load the necessary information from
Youtube's API, we will be sending multiple requests out concurrently and sometimes even chain them. Now technically, we could do this with
redux-thunk, but believe me when I tell you it was a huge pain. I know that because I later refactored the entire logic to use a more powerful middleware called redux-saga.
Sometimes I hear people say, that
redux-thunk is fine for simple applications. Well this may be true, but is your application really going to be simple?
What happens if you want to add additional functionality? Then you must refactor it and you’ll have quite a miserable time. So why not build the application with additional complexity in mind and pick a powerful solution in the first place?
Sure, we might write a little bit more code and we must learn a few new concepts, but we will have a very easy time to to maintain and extend your application. Don’t be lazy and always think about extensibility and maintainability when you build something. You don’t wanna make your life miserable after all. But that’s just my two cents 😁.
Also bear in mind that there are other alternatives such as redux-observable. This would also have been fine as well. Just pick something that is not too limited. I kind of like
redux-saga because it is quite straight forward.
2.3 Installing redux-saga in create-react-app
Head over to your terminal and run
Now that we installed
redux-saga, we need a directory where to put our sages.
- Create a new directory inside
src/storeand name it
- Create an
index.jsfile inside of the
sagasdirectory you just created
Put the following code inside sagas/
Our sagas will take care of all the asynchronous actions that are dispatched. To create a store, we bundle all our sagas into one single saga which we can call root saga. The concept is sort of comparable to combining reducers in
The first time I saw this, I didn’t understand anything at all, but let’s just finish the setup and then later on we can talk about what
redux-saga really is and what
2.4 Setting up Redux with redux-saga middleware
Almost done. Now, we have everything we need to create our store. We have a reducer (that currently doesn’t do anything) and we have a root saga that doesn’t do anything as well.
- Create a new file called
This file will do the
redux store setup and plug in our
redux-saga middleware. We put this into a separate file because we want a clean separation of concerns.
Here’s how you create a
Redux store with the
We first call a function from
createSagaMiddleware. After that we plug our middleware into our store by passing it as an argument to
Now, we only need our saga middleware to run our root saga (line 13) which is supposed to bundle all of the small sagas we will create in the future.
So far so good.
2.5 Plugging Redux DevTools into our Redux store
There’s still one thing we should do. While in development mode, we would like to see what actions are dispatched to our store and be able to go back in time. And no, you don’t need a the crazy professor from Back to the Future for this, you only need Redux DevTools extension.
Redux-DevTools is an extension you can install into you browser that shows you what kind of actions were dispatched.
Now to make this work, we need a little bit of config.
redux store setup like so:
What we do is, we get an object called
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ from our window object. This is something that the
Redux DevTools extension adds to your
DOM if you install the browser extension. If it’s not there, i.e. the extension is not installed, we just take the
compose function provided by
redux. By wrapping our
applyMiddleware in a
composeEnhancers call, we can travel back in time and replay actions that have happened using the browser extension.
Now I won’t go into detail what an enhancer is how that works because that’s kind of out of the scope of this tutorial. You’ll probably never write an
enhancer yourself, you just have to know how to plug it in.
Don’t forget to install the browser extension as described in the official documentation. Otherwise this setup is of no use.
2.6 Adding configured Redux store to our React application
The only thing that is left to do, is to plug our store into our application. Head over to your
index.js file in the root directory of your project.
Replace the contents of it with this.
Note that we wrap our application into a
Provider component from
redux. We need the
Provider component so that we can access our store in our components. The
Provider component basically allows
Redux to apply its magic, similar to how
BrowserRouter allows our application to use
Please run your application to make sure that everything is working
Everything should look like before, but under the hood a lot has changed.
3 Wrap Up
Wow, that was a lot of work. This is probably one of the hardest tutorials in this series. It’s going to get easier, that I can tell you.
Doing all this config stuff can be pretty daunting. Please bear in mind that you don’t need to have an in-depth understanding on how all the tools introduced here work.
You just need to know how to set them up. In fact, a lot of people (including myself), don’t understand the entire magic that’s going on under the hood.
I always have to look it up when I do it.
So the next time, you set up
React, you might come back to this tutorial because our setup is not specific to the
Youtube app we’re currently building.
As always you can find this project’s code on Github.Follow @productioncoder
Please follow me on Twitter @productioncoder to stay up-to-date. I’m happy to receive feedback of any kind.
If you are interested in more high-quality production-ready content, please enter your email below.