Infinite Scrolling in NextJs 13 Using Server Actions

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to implement infinite scrolling using server actions in Nexus 13. we're going to build on top of the application where we built a movie app and implemented a search functionality in pagination with these buttons where we could just paginate through different pages or search for a specific title we're going to turn this into something like so so instead of having the pagination buttons If you're going to have this a spinner at the end where it loads more movies and it's like an infinite scroll as as the user Scrolls down it fetches more movies but we have also preserved our search functionality so if you go ahead and search for a specific term it still changes that URL features that based on that specific term and then again you can still infinite scroll but keep that search term or query also as part of your data fetching so let's jump into the code and see how we have implemented this okay so if you're going to continue where we left off in the previous video by the way if you haven't seen that video I'm going to link it in the card somewhere so uh you can watch that first to know how we get where we are now and then continue from this point where we're going to refactor our code to use infinite scrolling instead of pagination buttons so let's just jump into the movies page where we're actually fetching some data using this git movies function this was a function that we implemented inside of our lib folder this is talking to our database to fetching some data it also implements the search functionality for us so going back to our app and movies in page if you're using that function to fit some movies right inside of our server components and if you're just passing it down here or mapping over it to just render these list items inside of this grid component okay now what we're going to do here is to actually create a server action and call this get movies function inside of that server action and the reason why we're doing it is that we not only want to call that server action from inside our server component but we want to be able to also call that same fetching function or server action from a client component where we're holding an array of our movies that's the only way we can have an infinite scroll so we fetch the first 10 movies from the server we pass it as the initial data or state to our arrays of movies on the client side and then as the user Scrolls down we're going to fetch more movies and append them to that same array so we should be able to also call that server action from the client component server actions are the best thing for this there are basically functions that you define on the server they run on the server but you can call them from server components or client component so the first step is to create this action inside the movies I'm going to create this action.ts file let me just rename this to actions that indicates we can have more than one action in this file now the convention is you would put this use server directive up top this is only meant to run on the server this is the convention for defining several actions now inside of it I'm exporting a fetch movies function this is going to be our server action and inside of it I'm calling this get movies functions we saw earlier this is the function we defined inside our library this is our database access the function that searches for movies now let's see what this error is okay we have to go to the get movies and actually make this page and limit optional it's expecting some parameters that we are not passing in here so we're going to pass a page and a search query to this fetch movies server action and then this is going to just call this get movies pass on those pages and search term and then get the movies back and pass it back to whoever it's calling it whether you're calling it from our server components or client component so let me just close this off and that going back inside of our page so what we want to do here instead of calling this get movies we want to call the fetch movies which is from our actions now we don't require any limit there and inside of our server component the idea as I just mentioned is to just get the first page for that initial render get the movies pass them to our client components which is just the list of movies and then the infinite scrolling is going to happen after that so if you don't need the page I'm going to just clean this up we're not going to change the limit we just want to get the search and the search is only to persist any query that the user has made so we're not losing that query if you're doing the infinite scroll and this is going to return the movies not inside of an object as you can see I'm getting an error here because I have to enable or pass in this experimental flag for Server actions at the time of this recording server actions are still in Alpha release if you want to use them you need to pass in this experimental flag to your next config.js let me just go ahead and stop to This Server and rerun the dev server to pick up this new changes so the first step was to Define This Server action and call this inside of our server component let me just get rid of that import there and we no longer need these navigation or pagination buttons so let me just get rid of those as well now down here if you're passing that that movies that we just it's returned from our server action down here inside of this list so if I go refresh and go to the movies page we should be able to see the first page of our movies now the next step is that I want to extract this part of our unordered list and put it inside of a component where not only we can hold an array of movies to then plug it inside of this grid but all but also Implement a spinner and also an intersection Observer where we can watch that spinner and then fetch more movies using the same server action that we created so inside of our movies I'm going to create a component called infinite scroll movies dot TSX and inside of it let me just copy some code and I'm going to explain what I'm doing here so let me just save this go back to our page and actually import it here and I'm going to explain what I'm doing in a second just bear with me for a second let's now review what's happening inside of this infinite scroll movie component let me just close the terminal so if you have more room over here now from a high level what it is doing is that it's rendering that same array of movies down here and all I have added or appended at the end is this loading spinner so this is a loading spinner that will be attached to the end of our list now up here I have initiated a state inside of this client component so this is a client component and I have initialized this estate with some initial movies this is what we are fetching inside of our server component so inside of our page when we are running this page we are fetching some movies and we want to pass these movies down to our client component so let's go initial movies and then pass this movies down to this component now to preserve the search when we are actually also fetching more data we pass in this search parameters or query that was passed in as a search prompt to our pitch component down to our client component okay so we are initializing a state with some initial data that's coming from the server and the idea is we render them as an array or a list of movies at the end we have a spinner and what we want to do is that anytime that that spinner comes into the viewport we want to actually fetch more data but before we get to that part we need to fix something about the data we're passing into this client component now inside of our page this is a server component where we are fetching the initial batch of movies and passing them down to this component which is a client component so if you're crossing the boundary between the server and the client which means this data needs to be serialized for this if we go back to where we're actually implementing this function inside of our lib folder this is where we are actually returning data from our database now before returning it to the client side we need to serialize this so I can just call json.stringify and then wrap this whole thing with a json.parse so we are stringifying this result that comes back from mongodb because it contains data such as object IDs and dates and stuff that may not be uh a string so if you're stringifying it first and then parsing it back to an object so if you're still getting an array of objects with that out of the way let's just move on to the next step which is actually implementing an intersection Observer that watches that spinner and anytime that it comes inside the viewport we want to fetch more data for this I'm using a library called react intersection Observer it is using react hooks so you can get this use in view hook and it gives you back some ref and in View Property which you can check past the ref to specific elements that you want to observe and then once that specific element is inside your viewport you get this in view you can check it and v in our application can check it to fetch more data so this is what we're doing down here I am getting this use in view hook I'm getting the ref and the in-view property I'm passing that riff down to my loading spinner as a ref and inside of my use effect anytime that this in view changes I want to run this effect but I don't want to load anytime these changes I only want to load if it is actually in view because with intersection Observer anytime that this element comes to the viewport it gets triggered or when it leaves or exits the viewport it also gets triggered I don't want to trigger any loading when it's exiting I just want to see when it comes to the viewport now if you're not familiar with intersection Observer I do have a video on the channel where I dive deeper into how you would go about using it and also implementing it implementing it inside react so I'll link that video in the cart so you can watch that if you're not comfortable with it but this hook makes it very easy to use intersection Observer under the hood and just check to see if this specific element is inside of the viewport and if it is we're calling this load more movies function now this is a function that I've defined right here it's an asynchronous function all it does is that it fetches some movies using that same server action but before we do that we're going to actually want to fetch the next page because on the initial load from the server we got the first page if we go to the fetch movie server action if you don't pass any page parameter to this fetch movies it just Returns the first page now inside of our page component we didn't pass in any page so we just got the first page now depending on whether or not the user was actually searching for a specific term we did also send this search down there now from inside of here we already have the first page as the initial movies set for our state now when we want to load again we want to load the next page so the first thing that we do is to get it this page state that we are holding also inside of this component add one to it and then call this fetch movies this is our server action and the beauty is that you can call this function from your client components so it's the same function we called it from our server and now we're calling it from our client component we pass in the search that was passed to us as a prop we're just forwarding it to persist any search query that the user had and we're going to pass the page to this next page we created here now if we get any movies back we're going to actually change the page to be that next page now and then we're going to set our movies this is the local state for the array of movies by actually spreading over the previous movies and then appending the new movies at the end of it so therefore we have the first 10 movies coming from the server and then now that we are scrolling and fetching more data we're going to fetch 10 more data and then appending it to the same list and this is all we are doing inside of this component now I have a little to do note down here if you wanted to extend this or actually fix this error you have to wrap this load more movies inside of a used callback and pass it to this dependency array for this use effect a little side note for this little squiggly line that we have down here now if I save this and actually go to our application and refresh the page to get the new code if I scroll down we should be able to see that spinner and actually a new batch of movies being fetched from our server action and append it to our list of arrays now if I go ahead and search for something down here even though we are moving the user to that URL and as a refresher we were using this search component inside of our page which was just rendering an input listening to changes on that input debouncing the user input and then pushing the user to this new URL so this is what we were doing on the search but even though we pushed the user to this new URL and we have already fetched the data this component doesn't change now the reason why this is happening is that the result of This Server component is now cached inside of the browser this is something that's called the router cache which is a next jss specific cache it restores the result of your react server component payloads and even though the data down there has changed it is the component hasn't changed so it's still using the same component now you can go to dexjs documentation where they actually talk about this different caching levels if you go to this caching section you can see there are four different uh caches or levels of caching happening from your server to your client the router cache is what I was just explaining and if you click on it they explain more about it how you can actually invalidate this cache now one way is to invalidate this cache inside of your server actions if you're using one to revalidate a specific path or tag or call router.refresh another trick that seems to be doing it is to pass in a key to your component so if I pass in a key over here let's say start with math.random if I now pass this in what happens is that this component is going to be different anytime so therefore if I now refresh this movies to go back to the same page let's say I want to get rid of that value over there too so let's say I have already scrolled down and fetched some movies now the user comes back up and wants to search for something else now this time because of this key react is actually going to re-render this component it's not going to use uh the server cache or I'm sorry the router cache inside of the browser so therefore we would then see this new term being reflected down in the form and then from that point on we can still scroll to get more data now to be more robust you can use the uuid package instead of math.random so you can just install the uuid package and create a unique ID for the key here as your honored list or the grid list item for this component so therefore it's not going to be stale anytime that your users actually search for a new term this is going to get recreated that's a wrap for this video folks we implemented infinite scroll link using server actions which allowed us to use the same function to fetch some movies on the server but also call that same function on the client this allowed us to attach an intersection Observer to a spinner we had at the end of our list to call that same server action to fetch more movies so that we can append it to the array or the list of our movies now there are different ways probably to implement infinite scrolling this is what I could come up with to implement this in a way that works if you can think of a different way to improve this functionality hit me up in the comments also if you have any questions hit me up in the comments like always if you're interested in learning Nexus 13 you know the drill there's a link in the description check it out let me know if you have any questions and until next time bye
Info
Channel: Hamed Bahram
Views: 9,200
Rating: undefined out of 5
Keywords:
Id: IFYFezylQlI
Channel Id: undefined
Length: 17min 58sec (1078 seconds)
Published: Sat Aug 19 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.