Build Youtube in React 36: consecutive requests for related videos
Let’s continue where we left off and continue with creating consecutive requests.
2 Displaying related videos in Youtube
2.1. Consecutive network requests in Redux saga
Let’s create a new function inside
src/store/sagas/watch.js that will make the consecutive requests:
You probably noticed that we have some duplicate logic. We have parsing logic in our
reducer and in
In both places, we are filtering out the
search response and get the
video ids of the related videos. This is one of the huge drawbacks of consecutive requests. Sometimes they require parsing the response of the previous request. This is sort of an anti-pattern but cannot be avoided in this case unless we update our
Youtube API does not support
GraphQL, so we I guess we have to live with these two duplicate lines of code. Now you might say, we might as well pass the parsed
related video ids down to our reducer. Like so we would not have duplicate logic. Well yes, but then we are parsing a network request response in one of our
sagas. This is not ideal either.
So you see, building
Youtube with the given
REST API has its caveats.
After we have the
related video ids, we create a new video detail request for each
id. Fortunately we can recycle our
function. We are using the
all effect which has a similar semantics like
Promise.all. Once we get the response, we dispatch the
VIDEO_DETAILS_SUCCESS action if we are successful. If we fail, we dispatch the
We fire theses requests, once we have the result from our
fetchWatchDetails requests back.
We do this after we dispatch the
WACH_DETAILS_SUCCESS action. Like so, we can chain the requests together.
2.2. Video details reducer
Just one more thing to do, we need to store the responses of our consecutive requests in our global state. Since we just fetch some videos, we put the results into our big videos dictionary, ie. in
Let’s write our little
Put the following code in your
Since we are using the
all effect, we get array of responses back. As a security precaution, we first filter the responses by its kind and extract only the responses of type y
This will be handy later on, believe me. After that, we build a small video “dictionary” where we associate each video with its
video id. We are using the
function for this.
Once we are done, we merge our new videos into our
Now we only need to make use of it in our
We just need to add an additional
2.3. Adding a related videos selector
Now that we have our videos in our state, we should provide a
selector to decouple our components from the global state.
As recommended by Dan Abramov, we colocate our selectors with our reducers.
We create a little helper function
returns the related
video ids for a specific video. We just a
ternary expression here to be safe in case we don’t have a
related object for a particular video id yet.
After that, we create our
selector where we iterate over the
video ids and pick the appropriate video from our
Theoretically there could be a case where we know the
related video id but where we haven’t loaded the video yet.
Therefore, we append a
filter(video => video) expression which kicks out all
null values in the array we
2.4. Pulling related videos into WatchContent
Wow that was a lot of work. Let’s make use of it in our
WatchContent component and pull the related videos from our
Redux state in.
Let’s pass our new prop down to the
RelatedVideos component where the actual work is done.
2.5. Updating related videos component
RelatedVideos component currently only contains hard-coded content. We need to change this.
First we check whether we the videos passed as
props and if the
videos array is also not empty.
The first element in the
videos array will be displayed in the
NextUpVideo component. All other videos (i.e. all videos starting from
props.videos) are put into a horizontal
We pass the
VideoPreview component a pathname and a
search prop so the user gets redirected when he/she clicks on it.
Let’s see how well we’re doing. Click on the image to see it in high resolution.
Well, that’s not too bad. But there are two things we still need to do.
First of all we need a little bit of space between videos in the right column. Second, we don’t show the next up video yet.
2.6. Updating the spacing between related videos
Let’s tackle the spacing problem first. Since the top element in our
VideoPreview component is now a react-router
<Link> element, our
SCSS don’t do anything any more.
Here’s what we have.
We’re only applying a
margin-top to the direct descendants. The
<Link> element gets converted into an anchor tag (
<a> tag) which is an
inline element and which ignores all top or
bottom padding / margins. We can do a quick fix by just targeting all direct descendant
<div>s that live inside the
I’ve made the
margin-top value a little bit larger, so it looks better.
2.7. Displaying the next video
NextUpVideo component isn’t showing anything because we haven’t made it dynamic yet. This is a matter of changing one line of code. We just need to pass on the
video prop to the
VideoPreview component that lives inside the
2.8. Fixing issues with react-router
Have you ever tried to clicked on one of the videos in the related videos section?
new video is shown, but somehow the related videos section remains empty.
Why is that?
If you click on the video, the only thing that changes in the
URL is the
So suppose you navigate from
the only thing that changes is the search parameter
React will re render the components but no
lifecycle hooks like
componentDidUpdate is called.
But this is where we perform all our network requests.
To get around this issue, we need to force
Watch to unmount and remount again, our lifecycle methods reach out to the network.
To do so, all we have to do is to pass something to
props that changes whenever the search params change.
Add the following code in your
location.key element changes every time the
URL is updated somehow (path changes, search parameter changes).
3 Wrap Up
Nice, that’s it.
We successfully display the related videos.
Click on the image to see it in high resolution.
However, we currently don’t provide detailed information on the video’s channel. We will do that in the next tutorial.
We also need to fetch the comments as well.
As always, thanks for reading.
You can find all the 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.