
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
In this lesson, we explore how to create a movie application with trending functionality using React. The focus is on fetching top movies from a database and rendering them dynamically on the homepage based on user searches and trends.
useEffect
to call fetching functions at component mount.00:00:02 In this lesson, we'll first create a function that queries the AppRide database to retrieve the top movies our users have searched for.
00:00:11 And then we'll display it in a cool Netflix-like carousel at the top.
00:00:15 So first things first, let's collapse this updateSearchCount function.
00:00:20 I'll zoom out a bit.
00:00:22 And right beneath it, create a new function, export const getTrendingMovies.
00:00:31 It'll be equal to an asynchronous function.
00:00:34 And this one doesn't have to get any props, but it'll just return a single promise of trending movie array, just like this,
00:00:44 or undefined.
00:00:46 in case something goes wrong.
00:00:48 So here we can open up a try and catch block.
00:00:53 In the catch, if there's an error, we'll simply console log that error.
00:01:00 and return undefined, but in the try, we'll actually try to list out those documents.
00:01:06 And we have already done that at the top of the update search count, because to update, we first have to fetch them.
00:01:12 So let me copy this starting part and paste it here.
00:01:17 Const result is equal to await database.listDocuments, database ID, collection ID, And this time I'll say query.limit to five,
00:01:30 so we only want to get the first five elements, and query.orderDescending based on the count field.
00:01:40 So we only want to show the top five movies that people have searched for sorted by the count.
00:01:48 And we can say return result.documents.
00:01:53 Just to make TypeScript happy, we can say as unknown as trending movie array.
00:02:00 This way TypeScript will know exactly what we're returning.
00:02:04 Next, we can call this function within our homepage.
00:02:07 So head over into index.tsx.
00:02:11 I'll zoom it out once again, so you can see a bit better.
00:02:14 And right above the first useFetch call, we're going to add the second const.
00:02:21 We know how it works.
00:02:22 You can call it useFetch, but this time to it, we're going to pass the getTrending movies instead of fetch movies, and we get back the same things.
00:02:35 The data, which this time we can rename to trending movies, the loading, which we can rename to trending loading, as well as the error,
00:02:45 which we can rename to trending error.
00:02:48 Now, just below where we have the activity indicator, we can say if movie's loading, or trending loading and same for the error if there is movies error
00:03:02 or if there is trending error show an error that error can be movies error or maybe it is trending error Question mark dot message here to the search bar.
00:03:14 We don't have to pass the value because we're searching within the search page.
00:03:18 So we can make this value optional right here.
00:03:22 And what else is optional on press placeholder?
00:03:25 What are we missing on change text?
00:03:28 Yeah, we don't need it right here in the homepage.
00:03:31 Next, right below the search bar, I'll say, if trending movies exist, so if trending movies, then show a view.
00:03:44 This view will have a class name equal to margin top of 10, and we'll render a text element.
00:03:55 That'll say trending movies.
00:03:58 Of course, let's go ahead and give it a class name so we can see it of text-lg as well as text-white, font-bold and margin-bottom of three.
00:04:11 Let's open up our terminal and reload the app.
00:04:14 Just to see where we are.
00:04:16 Sometimes it gets stuck, so you have to reload it.
00:04:18 You know that by now, don't you?
00:04:20 And now you can see trending movies title right here below the search.
00:04:24 So how are we going to render the trending movies?
00:04:27 Well, believe it or not, it's going to be a new flat list to which we can pass the trending movies as the data.
00:04:36 And I'll pass the render item to be equal to, as before, we'll destructure the item as well as the index from this function.
00:04:46 And then for each item, for now, I'll simply return the item.title.
00:04:53 But of course we have to put it within a text.
00:04:55 So let me actually expand this and return a text element.
00:05:00 within which I'll render the item.title.
00:05:04 And let's give it a class name equal to text-white, text-sm, just so we can see it.
00:05:12 Now, if we properly close this flat list, you'll be able to see three top movies, Avengers Infinity War, three times.
00:05:20 Let's style it a bit by giving it a class name of margin-bottom of four and margin-top of three.
00:05:27 And I'll put each one of these props in a new line, just so it's easier to see what's happening.
00:05:32 There we go.
00:05:33 Data, render item, and then we render a text.
00:05:38 Below render item, we'll have the key extractor.
00:05:41 It is a mandatory thing where we get access to the item.
00:05:46 And the ID will be coming from item.movie underscore ID.
00:05:53 and currently, the top three movies all seem to be Avengers Infinity War.
00:05:58 I guess that's because for all three of these, it saved that as the title.
00:06:02 Let me actually delete those documents and let's try it one more time.
00:06:06 Now, there should be no latest movies.
00:06:10 So now, if I reload my application once again, right off the bat, you'll see an error right here saying that virtualized lists should never be nested inside
00:06:21 plain scroll views with the same orientation because it can break windowing and other functionality.
00:06:27 What this means is that we cannot have at least not the list with the same orientation.
00:06:33 But don't worry about that for now, because very soon we'll change the orientation of this flat list to horizontal, because that'll make it look more like this.
00:06:41 So for now, if I go back to my app, go to search and try with something like avatar, and then I delete that and maybe search for alien.
00:06:52 Okay.
00:06:53 And now if I go back to app right, looks like the metrics are not getting added.
00:06:57 So let's debug it together.
00:06:59 I love it when something obvious doesn't work when I'm recording because it gives me the opportunity to go back into the code.
00:07:06 And I think that sometimes you can learn more that way than just watching me code everything out because you can see exactly how I would approach the debugging process.
00:07:16 First, we have to ask ourselves, where is the error coming from?
00:07:20 In this case, we know that the documents are not getting added to the AppPride database, so we have to ask ourselves, where is that within our code?
00:07:28 And that is within the search page.
00:07:30 So if you head over to the search page, you'll see that we have a single use effect.
00:07:34 Now, within this use effect, we have both awaitLoadMovies as well as updateSearchCount.
00:07:41 And these two can race together and we never get back the meaningful results.
00:07:46 So we have to split them into two separate use effects.
00:07:49 So I'll copy this if statement and within this first use effect that gets executed whenever the search query gets changed,
00:07:58 Here, we just want to awaitLoadMovies.
00:08:01 But in the second one that I'll create right now, useEffect, where we have a callback function, this one will change whenever the movies themselves change.
00:08:14 And here, we want to check if movies.length is greater than zero.
00:08:18 And if movieFirst exists, then we want to open up a code block here and we can simply call the updateSearchCount without the use effect like this.
00:08:28 Now, if we go ahead and search for something like avatar, we'll get back the movies.
00:08:34 I'll go ahead and search for something like, let's do cats.
00:08:40 There we go.
00:08:41 And if I head back to AppRide, you'll see that we have two different movies stored right here.
00:08:46 We might as well go for the third one.
00:08:48 So I'll go with Iron Man.
00:08:52 There we go.
00:08:54 Looking good.
00:08:56 And if I reload, it gets saved.
00:08:58 And of course, what we care about is what if another user searches for a similar movie?
00:09:03 So if another user searches for Avatar, for example, there we go.
00:09:08 Does the count get updated?
00:09:11 And this time it does.
00:09:13 So now, if we go back to the homepage and head back over here, where we're trying to show a flat list of the top movies.
00:09:22 Let me just make sure to reload the page.
00:09:24 You can see that the right here, we get three different movies.
00:09:28 Avatar, Cats, and Iron Man, which is great.
00:09:31 That means that our trending functionality is kind of working.
00:09:34 But of course, we have to improve it further.
00:09:37 Check this out.
00:09:38 We can pass just a single prop called horizontal, and if you just pass it like this and save it, immediately the orientation will change to horizontal.
00:09:49 We can also say shows horizontal scroll indicator and set it to false.
00:09:55 And we can also render the item separator component.
00:09:59 And I'll make it equal to a simple view that is self-closing.
00:10:05 and has a class name equal to W of 4. Now we can see that this looks a bit better.
00:10:11 Oh, and this latest movies was supposed to be just above the other flat list, not this one.
00:10:17 So I'll go below this one and here I can paste it.
00:10:21 It says latest movies and right here at the top, we have trending movies.
00:10:26 Great.
00:10:26 But of course, we don't just want to show three pieces of text.
00:10:30 We want to show full on cards that look like this with these top trending numbers.
00:10:36 So to do that, let's create a new component in the components folder.
00:10:41 And let me call it trending card.
00:10:47 run rnfe to quickly create it and now instead of this text where we're rendering the item title we can render the trending card just like this a self-closing
00:11:00 trending card component to which we can pass over the movie equal to item this is an alternative way of just spreading everything out Sometimes this is
00:11:11 preferable because then you can console log the entire movie itself and then know what properties does it have.
00:11:16 And let's also pass the index of that movie equal to index so we can show that number.
00:11:22 Now let's head over into the trending card and let's get it implemented.
00:11:26 As with the cards before, I'll wrap this card with a link because we want to make sure that the entire card is clickable and that it leads to the movie
00:11:34 details page.
00:11:35 So I'll add an href of forward slash movies forward slash movie underscore ID.
00:11:42 And I'll say as child because we want the entire touchable opacity to be clickable.
00:11:48 So it'll inherit link properties.
00:11:50 Now, where is this movie ID coming from?
00:11:53 Well, we can destructure the movie right here from props.
00:11:57 And from the movie, we can further destructure the movie ID, the title, and the poster URL.
00:12:04 And outside of this movie destructuring, we can also get the index.
00:12:09 And we can say that all of these are of a type, trending, Now, within each link, let's render a touchable opacity.
00:12:19 It'll have a class name equal to W-32, relative, and padding left of five.
00:12:27 And immediately within it, we can render an image.
00:12:30 This image will have a source.
00:12:33 equal to URI is Poster underscore URL.
00:12:37 A class name equal to W32H48 and rounded dash LG with a resize mode equal to cover.
00:12:49 And there we go.
00:12:50 Now we can see the cover photos or the posters for the top three searched movies.
00:12:55 Right below it, I'll render another view.
00:12:58 And this view will be absolutely positioned.
00:13:02 So I'll give it a class name of absolute.
00:13:04 That's because it'll serve as an overlay over the poster.
00:13:08 So somewhere at the bottom left, we want to show that number 1, 2, 3. So I'll say bottom dash 9 minus left dash 3.5, padding X of 2, padding Y of 1, and
00:13:23 the rounded dash full.
00:13:24 And now within it, we want to achieve some kind of a masked layout.
00:13:28 I'm not sure if you can see it here, but the number here will be a bit masked, like it is under some kind of a darker mask,
00:13:34 like it'll have a slight gradient.
00:13:37 And we can do that using a package called Masked View.
00:13:41 This one right here has about 265,000 downloads.
00:13:45 And as the package says, it creates a masked view where the text appears as a cutout over an image.
00:13:51 So let's simply copy the installation command that is npm install at react-native-mask-view forward slash mask-view.
00:14:00 While it is installing, we can put it to use right here within this view.
00:14:04 I'll create another masked view and you have to provide a mask element.
00:14:10 In this case, it'll be a single piece of text.
00:14:15 So I'll do it right here.
00:14:18 Text, inside of which I'll render the index plus one.
00:14:21 So that we don't start at zero, we start at one.
00:14:24 Of course, I'll give this index a class name equal to font-gold, text-white, and text-6xl.
00:14:33 We want to make it extra large.
00:14:34 Let's fix the class name spelling right here.
00:14:37 And within the mask view, I will render the image that'll have a source.
00:14:43 equal to images coming from constants dot ranking gradient with a class name of size-14 and a resize mode set to cover.
00:14:58 Now let's fix a typo where we have it.
00:15:01 There we go.
00:15:01 I think we're good.
00:15:03 And take a look at these numbers right here.
00:15:06 Looking good.
00:15:07 One, two, three.
00:15:09 And if you try scrolling, you'll see that this one has a horizontal scroll, whereas you can scroll the entire page up and down.
00:15:16 So before, we had that virtualized list error because we had two vertical lists in the same file or in the same screen, should I say,
00:15:25 but now one is horizontal and one is vertical.
00:15:28 So we're good.
00:15:29 Now, just below this view, not the mask view, but the other one, we can render a piece of text that'll simply render the title of the movie.
00:15:38 And it'll have a class name equal to text-sm, font-bold, margin-top of 2, and text-light 200. And we can also make it take two lines maximum.
00:15:54 So number of lines, two.
00:15:56 And with that, you have implemented this trending card layout, which is looking great.
00:16:01 So if we go back to the index, no warnings or errors here.
00:16:05 And if I go ahead and search for a new movie, like Avengers, there we go.
00:16:10 And go back to home and reload.
00:16:13 You have to keep in mind this search functionality update is not something that has to happen in real time.
00:16:19 When you open the app again, you'll be able to see all the new searches that people have made.
00:16:23 And there we go, a fourth number appeared right here, Avengers.
00:16:27 That is perfect.
00:16:28 And the more users search for the same movies, the higher they will rank.
00:16:32 Wonderful.
00:16:33 Now you have not only implemented the typical API fetch call, but also implemented a backend as a service tool that allowed us to store a persistent data
00:16:43 within a database that we use to then show the top trending movies.
00:16:48 Great job.