Build Youtube in React 24: Create reducer for most popular videos
1 Overview
We already created the request
, actions
and sagas
for the most popular video endpoint.
However, we still lack a reducer that handles the MOST_POPULAR_VIDEOS
action.
2 Video reducer
2.1 Creating the video reducer
Since our video data will live in its own sub reducer
, let’s create a new file for it.
- Create a new file called
videos.js
and put it insidesrc/store/reducers.
First, we set up the basic structure of our reducer
.
Our reducer's
initial state consists of the byId
and mostPopular
object which are both empty. That makes sense right? Because at the beginning, we haven’t yet fetched any information.
Currently, we’re only handling the case when our MOST_POPULAR_SUCCESS
case, i.e. if we successfully receive the data.
To not clutter our reducer, we put all the logic inside an own method called reduceFetchMostPopularVideos
.
Before you read the code, please have a look again at the JSON response the server returns so it’s clear what this function is doing.
At first, we create an object called videoMap
. videoMap
is some sort of dictionary where we associate each video with its id
. This video map will be merged into our byId
object later on.
And here comes the interesting part. If we send along a nextPageToken
, the server’s response will contain a prevToken
property. So by checking whether prevToken
is there, we know whether we already fetched some videos from this endpoint or not. If prevToken
is not there, then we haven’t stored anything from the endpoint yet.
If we do have a prevPage
token, we don’t want to throw away the videos we already fetched. In this case, we’re just appending the new videos to the videos we already have inside mostPopularVideos.items
array.
Finally, we update the mostPopularVideos
object by storing the total amount of videos we could fetch (response.pageInfo.totalResults
), the next page token
and the items
array. items
is an array that contains video ids
. The actual video details are all stored inside the byId
object in our global state.
Like so, we have all the video details at one place.
2.2. Combining reducers
Now, we only have to plug in our videos reducer into our root
reducer.
Head over to the src/store/reducers/index.js
file and add it to our combineReducer
statement.
This essentially says: our global reducer
is composed of several sub reducers
. Each sub reducer is responsible for one particular part of the state. The api
reducer will be responsible for the api
object inside our global state. The videosReducer
will handle everything that will go inside videos
.
The sub reducers
don’t know each other and they also don’t need to. If you frequently think about accessing another part of the state from a sub reducer
then you should think about refactoring your state altogether. We want a clear separation of concerns that leads to low coupling.
Otherwise it is pretty hard to maintain it.
2.3. Using our fetching logic
Now that we have all the logic in place, we just have to use it. Our Home
component will display the most popular videos, so let’s go ahead and fetch some data.
What did we do? Well first of all, we created two new functions: mapStateToProps
and mapDispatchToProps
.
The mapStateToProps
function is used to get the api.libraryLoaded
field from our global state. We use the selector getYoutubeLibraryLoaded
for this. The mapDispatchToProps
function allows our component to start the fetching process of the most popular videos by dispatching an action. Note that we use Redux' connect
helper in the export default
statement.
Also note that we make use of two lifecycle methods. The first one is componentDidMount
. componentDidMount
runs once our component gets plugged into the DOM
. This lifecycle method is typically used for reaching out to the network.
In case we already loaded the Youtube
library, we immediately start fetching the most popular videos. However, there’s one important detail to note. Remember that we have to pull in the Youtube
library from a CDN
asynchronously. So oftentimes if componentDidMount
is called, we haven’t yet loaded the Youtube
library. Without the library, we cannot reach out to the Youtube API
. This is why we rely on componentDidUpdate
.
When our Youtube library
is finally loaded, componentDidUpdate
gets called because we sort of “subscribed” to the libraryLoaded
property from our global state via the youtubeLibraryLoaded
selector. In componentDidUpdate
, we check whether it was getYoutubeLibraryLoaded
that was updated and not something else. If this is the case, we start fetching the most popular videos.
Well if the library is not loaded when the component is mounted, why do we use componentDidMount
anyway? Remember that we will have different pages in our app. So a user might navigate back from another component (e.g. Watch
) to our Home feed
. In this case, we already loaded the Youtube
library and therefore we can make the request immediately.
2.4. Testing our Youtube most popular videos fetching workflow
Remember that one tutorial where we added support for the Redux Devtools
?
Now we will make use of it to verify that our magic works.
Start your app and click the Redux Devtools
icon.
When you start the app, you should see something like this.
Click on the image to see it in high resolution.

3 Wrap Up
Yeah, it actually worked. We’re successfully fetching the most popular videos from the Youtube
endpoint and store it in our Redux state
.
Right now, our app still looks a little bit boring because haven’t populated our components with the data yet.
Thanks for taking the time to read this tutorial. You’re a real fan.
You can find all the code in our Github repository.
Follow @productioncoderPlease 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.
Recent Comments