Build Youtube in React 23: fetching most popular videos
1. Overview
In the last tutorial, we created some helper functions to make our life easier when it comes to creating actions and to fetching data.
Now, we will finally make use and fetch some data for the Home
feed.
2. Most popular videos request, actions and sagas
2.1. Creating fetch most popular videos action
Let’s put this logic into a file with a self-explanatory name:
- Create a new file called
video.js
insidesrc/store/actions
Adding actions
is now pretty straight forward.
By calling createRequestTypes
, we store an object with three fields
inside MOST_POPULAR
, that is
The request function of mostPopular
takes three
parameters. First we want to dynamically tell the action how many videos we want to fetch. Since the video description can be quite long, we also want to control whether we load it or not. If we don’t need it, it makes sense to not load it because we will have a lower response time.
We also pass the a next page token in case we want to make use of Youtube's
pagination feature.
2.2 Creating most popular videos request
We now have the action that is supposed to kick off the entire process. But we haven’t yet defined the request and specified its payload. Let’s do that now. With the help of the Youtube's
boilerplate code, this will be quite straight forward. Add the following function to your store/api/youtube-api.js
file.
As you can see we are just performing a standard GET
call against the /videos
endpoint and pass a few parameters. We want to get back the snippet
, the video’s statistics
(so we can show the view count) and the video’s content details
. Please refer to the JSON
response shown above to see what snippet, statistics
and contentDetails
contain.
We also pass a quite cryptic string for the field parameter to prevent over fetching and to get a faster response. We adapt the fields string depending on whether we want to load the description or not.
2.3 Fetching data with sagas
We have the actions
, we have the request, but we don’t have the sagas
that will do the actual work. Let’s quickly set this one up.
- Create a new file called
video.js
insidesrc/store/sagas
If you think about it, our overall data fetching workflow is pretty much the same. First we execute the request and wait for the result. If the request succeeded, we dispatch an action with whose action.type field ends with SUCCESS
. If the request fails, we dispatch an action whose action.type filed ends with a FAILURE
.
Let’s create a helper function for that which we can use over and over again. Add the following function to your src/store/sagas/index.js
.
The fetchEntity
function takes in three parameters. The first one is the request
function, i.e. a function that returns a promise. Typically this function is somehow constructed by the Youtube client library
. The second parameter is an entity object. By entity, I mean an object that has a request
, success
and failure
function. That’s pretty much anything we import from src/store/actions
. Remember that we are always bundling three different action creators functions together in an object because we always have the REQUEST
, SUCCESS
or FAILURE
case.
The ...args
makes the function variadic. This means that we can call this function with an arbitrary amount of arguments. Sometimes we want to pass additional information into our FAILURE
and SUCCESS
actions. Therefore, we allow an arbitrary amount of additional arguments.
The method itself is quite straight forward. It will execute the request and if it is successful, it dispatches the action returned by entity.success
. If it fails, it dispatches the action returned by entity.failure
.
We will use the fetchEntity
method all the time from now on because we want our code base to stay DRY
.
2.4. Most popular videos sagas
Now that we have our fetchEntity
function in place, we just need to create a watcher
and a worker
saga. Head over to your src/store/sagas/video.js
file and add:
Once such an action is dispatched, we extract its payload. That is, the total amount of videos we should fetch from the endpoint, the next page token
(if any) and a flag that tells us whether to load the description or not. The watcher saga then passes on the actual work to a worker saga called fetchMostPopularVideos
. In here, we use the buildMostPopularVideos
function we defined earlier to construct a request.
You might have wondered why we use the bind
method here. Well, the redux-saga call effect
needs a function
as a parameter. When we use bind
, it will return a new function with already inserted parameters. We could have also used:
Once constructed, we pass the request to fetchEntity
which will execute it, wait for the result and dispatch the appropriate action when the request succeeds or fails.
2.5. Running our saga
We successfully defined our sagas
but we’re not running them. To run our sagas, we merge them together in our big root saga that will later be run in our store.
This is what the default export is for in src/store/sagas/index.js
We only need to instruct the middleware to run our watcher saga. If our watchMostPopularVideos
saga detects an action with the correct type (MOST_POPULAR_REQUEST
), it will create a worker saga that will load data from the Youtube
endpoint.
We use the all
effect to instruct our middleware to run the sagas we specify in the array.
By forking
all of the sagas, we tell the middleware to run all of them (currently just one, but more will follow) in parallel and not wait for any of them to finish. In fact, our watchMostPopularVideos
saga will never terminate because we will listen for new actions forever.
This is also why we created an infinite loop with while(true)
in our watcher saga.
3 Wrap Up
Good job, we’re done with the sagas.
However, we still need is the video reducer that updates our state once we receive data from the Youtube
endpoint.
You can find all the code in our Github repository.
As always thanks for reading.
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