Adding Search Feature in Server Components | NextJs 13

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to implement search functionality in react server components in Nexus 13 app router we're going to build on top of the application we created in the previous video where we looked at pagination in server components we were fetching some movies from our mongodb database and we had this next and previous buttons to kind of change and navigate between different pages of our application now if you haven't seen that video I'm going to include a link in the card so you can watch that first and see how we get to where we are here and in this video we're going to implement this search functionality where the user can just search for a specific movie by the title they can still paginate through the list with that search term or they can just use a search term to maybe search for a specific cast member in a movie all with setting URL parameters as a way to kind of hold this estate or this client side interactivity and communicate that back to to our server so let's jump into the code and see how we're implementing this together now where we left off in the previous video was implementing this page component which was inside of our movies that's responsible for rendering our movies page we were getting a list of our movies by calling this get movies function this was a function we implemented inside of our library so inside of our lib in mongodb we had a client.ts this is where we created a connection to our mongodb database by providing our mongodb URI as a connection string as a local environment variable and then we had this movies file where we kind of encapsulated all the functions that relate to our movies collection we created this get movies function where it was just performing a find query on the movies collection to find some movies limit them based on the limit that we're passing into this function if there is any or defaulting to only 10 movies as you can see here and then also skipping a specific number of pages depending on the page parameter that we're passing into this get movie so all in all what we were doing here is to reading this page and limit parameters from search prompts this is an object that's passed to your page component by next.js that holds uh your query strings or your url search parameters and we're just passing that down to this get movies function to get the movies and then render them down here now for the next and previous buttons we're just using links uh that would just push the user to a new link and set the page to the next page or to the previous page depending on whether you push the previous button or the next button now to implement the search functionality let's actually create a component maybe called search so I'm going to create a new component called search and then here what we're going to do is to return a component and let me just copy some code for the jsx or for the actual search input and then I'm going to also have to install hero icons I'm using here icons for uh my magnifying glass in the search input so let's just get this package installed let me just pmpm add Dash D and then your icons react okay let me just restart the dev server so here I am just rendering an input and I'm holding a local state to read the value and then change that state based on the on change so let's actually also bring in or react user State hook to set this text and let's just start from an M2 string we can also import this from react we're using hooks so we have to turn this into a client component let me just add the use client directive up top and save this uh sorry I just typed in texts here so this should now work let me just go back to my page component and create a div and bring in this search component that we created together let's go back to our page and now here if I refresh I should be able to see my search input okay great so we have this search input set over here where we can pass in some values and we're actually holding this locally in a react state let's now create an effect here where we can just log up anytime that this text changes we're going to just console log this text just to test everything out if I open up my console over here let me just make this bigger if I refresh and also refresh that if I put in any text here we can see it's being logged over here okay so we now have access to what the user is trying to search inside of this client component but how can we send a search term back to our page component where we're actually fetching our movies now if you're going to implement or use a similar concept as what we use to kind of communicate these different pages to our server which was through URL or URL search parameters now not only you can use the URL to hold this state of what page or how many limits of documents you want to return or what search term or query the user is trying to search for you can also expand on it if you want to implement more filters here for the search functionality you could just hold them up in the URL as a place to hold a state but also as a way to communicate user interaction from client components back to your server components or to your server where you're actually doing your data fetching so to do this let's actually go ahead and inside of this use effect use the router so let me just get the router from use router hook that we can get from next navigation just keep in mind that the router that we want to use inside of our app router comes from next navigation and not the next router the next router still works but it is for the pages router if you need to use this used router hook inside of the app directory you need to import it from next navigation so with the use of this router here maybe you can say anytime that this text changes or this search input changes we're going to actually push the user to movies and then we're going to pass a search parameter and we're going to just set it to this text okay and I guess this also needs to have the router to stop screaming at me so if I now go back to our application and start typing inside this search box you can see if you are now setting that URL search parameters up top which is going to communicate to our page component and then we can read this new search parameters and then pass it down here in get movies but before we do that one thing I want to implement here is that instead of just setting or changing the URL on every keystroke I want to debounce the user input so once they're done typing in then I want to change the url because if you're doing this on every single keystroke we are actually literally hammering our server or coring our database on every single keystroke and that's not a good user experience or a technical way of implementing or working with user inputs we want to be able to de-balance it so they might be starting typing in you can just delay that for 500 milliseconds or 750 milliseconds and then once they're done you're going to get determined then actually push them to that URL now to do that we're going to use a package called debounce we can search for use debounce this is a react hook which is going to allow you to debounce a value so let me just go ahead and install this let me just stop the dev server I'm going to go pmpm add use debounce I actually have a video on the channel where I talk about this in more details I'm going to also link it somewhere in the cart if you're interested to learn more about this but it's pretty easy to implement so all we need to do here is to create a debalanced value let's call it debounced and we're going to use use debounce and this takes in a value and the amount of time that you want to actually debounce this so I'm going to pass in this text state which is what the user is trying to actually search and then I'm going to delay that or debounce that for 500 seconds let's actually name this query so it makes more sense now down here I actually want to use this query so I'm going to use the bounce value instead of the text so anytime that the query changes this time now I want to pass that to the URL now going back to our application to test this out let me just also close this if I now start typing inside the search box as you can see it's going to take some time time before it actually hits the URL which is going to send a request or communicate this to our server component to fetch relevant movies now if I also try to delete this search term you can see it again takes in some time for me to finish typing and then clears out that search parameter now right now it just pass in nothing to our search parameter so what we can do instead of our use effect is maybe to actually see if the query is a truthy value and then set this search parameter and if it's not we're going to actually pass push them back to the movies page where we don't have any search parameter so if I now save this it should send us back to the movies page as you can see there so if I search again for our movie title it's going to take some time passing that search and then if I go ahead and delete this it's going to take us back to the movies page without any search parameters set now let's go back to the page component actually read this value that we're passing in here so similar to what we have done with the limits and page that we read from our search parameters I'm going to read the search if it's a string I'm going to actually use it otherwise undefined and what we can do here is to actually pass in a query to our function that we have defined before and set this to this search term that we are getting from our URL search parameter so it's a bit small here so if you're reading this search uh string from our search prams object that's passed into our page component and we're just passing it to our gitmovies function as a query so let's go back to our movies collection and actually implement this search Let me just copy some code over here so you don't have to watch me type okay let me explain what I've added to this get movies function here on top of the page and the limit parameters we were passing it before I'm also expecting this query this is the search term coming in from the client side so we can use it inside of our query to return relevant movies it's not defaulting to any value because the user can be on the first page just trying to paginate without actually searching for any specific term so there's no default value here that's why it's also marked as optional inside of this type now we're still doing the pagination with this skip variable we're creating here but instead of performing a find query on our collection I'm actually using mongodb aggregation pipelines to perform a full text search using this search stage now this will allow you to do a full text search using some fuzzy matching on any field that you want in this case I am providing a wild card character for my path which means that whatever search term that they pass in can be used to match against any field inside of my document or record for example it can be inside of the title of the movie it can be inside of the cast it can be inside of the full plot and whatnot you can also pass in a specific path for example if you want to only search within the title you can pass in the title here now the implementation detail of this search pipeline is a bit beyond the scope of this video but I'm going to include a link in the description if you're interested to learn more about this pipeline or about this aggregation feature in manga OTP but from a high level what we're doing here is we're creating this pipeline these are different queries you run against your database and here I have a stage for skipping a specific amount of document and also this limit and I'm also checking to see if I do have a query so if we are passing in a query I'm actually adding this stage to my pipeline which is just going to use this search stage to run that query against all of the fields with some fuzzy matching and then return some results which we are just getting in here and returning back to our page component so now that we have implemented this if I go back to the application and start searching for a specific topic this is going to set a search parameter this is going to send that URL to our server component which is going to perform this query to fetch a specific term inside of our database for example for a specific title or even a specific cast because I'm using this wild card character from my path which just searches for that term against all the fields inside of our documents in our movies collection but now there's a couple of problems in our app first of all if I now try to paginate if I click on this next button it actually wipes our search term out because it's just pushing the user to this URL so what we need to do here going back to our page where we are actually sitting in or using these links as our buttons I'm going to actually use a different way to set up the href for our links over here so if you look at the documentation for next.js there's two ways you can pass in an hdf to your link component one is to the way that we have already done is just passing it a string the other way is to just pass it in object where you can define a path name and then your query parameters and the reason why I'm doing this is I want to look to see if I do actually have a search set on the URL already and if I do I want to actually also use that together with the page and actually kind of sending them to the previous page or to the next page so I'm going to also do this for the next button uh down here so instead of passing in a string that doesn't take our search into account I'm just using a URL which makes it easier to also read both and if there's a search to read that or to set that as well or to keep it there while we're actually changing the page now with this if I refresh the page if I now search for let's say Bruce Lee I'm going to see that search term kicking in and if I click next not only I have that search term set but I'm also going to the next page which still is taking this search term into account let's search for something else now as you can see I spelled this wrong but the fuzzy match is actually actually bringing all the Rocky movies up and I can also go to the next page okay now that works but we still have another problem if I now refresh this page you can see the search term is wiped out and then after the bounce kicks in setting or query to an empty string or use effect is actually pushing the user back to the movies page so if you go to the search component what happens is that once I refresh the page this estate went back to being an empty string even though we had the search term up in the URL and then this used the bounce kicked into place after 500 milliseconds setting this Quarry the Quarry actually changed this runs and because there is no query term it's going to actually push the user to this movies now the first thing we need to do is to actually set or pass in the search parameter that's in the URL to this search component so we can initialize this estate with that term and then set it down here on the input so if the page is refreshed it is not going to actually wipe the search term off of the search input box so let's just go back to our page component where we are rendering this search we can pass in this search parameter that we got off the URL as a prop to this component so we can initialize our state with it so let me just pass in this search now inside of our search component I can expect to receive this search prop which is going to be search Let me just type this out it's going to be a string and a maybe even optional because maybe they don't send any search and then we can use this search to initialize our state which is then this text state which is the value of our input if I now search for a term let's say I also go to the second page if I now refresh the page something else actually happens as you can see up top it just wiped the page out and brought us back to the first page when we refresh the page this is also going to happen if you copy this link somewhere else and the reason why that's happening is that now that we are actually reading this initial value we're passing this search term from the URL as a prop to the search component to set inside of this search input what happens after this use effect runs because now the query has a value it actually goes ahead and pushes the user to this movies for slash search which doesn't have the page inside of it so if this is only on this search term without any page parameter set and you refresh it it works because it passes this search parameter that exists on the URL to this page component and if you copy this into a new page as I can show you here it's just going to land on that same page because this is persisted here and also down here but the problem is if we go ahead and have a pagination uh value up top in the URL as well and now if we refresh the page what happens is this kicks in inside of our use effect redirects the user back to search that query so it disregards that page that existed there so to bypass this problem we can actually use ref to disable the use effect from running on the initial render so I'm going to create a initial render ref I'm going to use the use ref Hook from react and I'm going to initialize this to true and then it's inside of our user effect I'm going to check to see if this is our initial or first render by checking the initial render dot current coming from this userf and if it is our first render I'm going to return effectively disabling this effect to kick in so if you're not actually using that page parameter that existed there so if I now save in here and actually go ahead to the second page let me also refresh this page now if I go ahead and click to go to the next page we can still see the second page also our search term and if I now refresh this because we are not going to run this effect on the first render it is going to keep that state for our search term and also our second page there and from this point on if you go forward or you go backward it still works you can just copy this link and the other user would end up at the same page with the same search term with the same pagination or page number as where you copied this now this is the benefits of using the URL as a state not only you can share it but also there is a history track inside of your browser so you can use the back and forward buttons now to just go or move in the history stack of the browser for different states of your application for different movies that you have here that's enough for this video folks we implemented server-side search functionality by linking client-side interaction to our server components through the URL this not only allowed us to hold some State up in the URL for our search and pagination but also communicate that to our server components where we are actually fetching data if you have any questions hit me up in the comments if you want to see more content specific to mongodb please let me know in the comments below maybe I create a specific full text search video for mongodb where we can add in more filters or facet search inside of our application using aggregation pipelines in mongodb if you're interested in learning xjs I do have a course there is a link in the description let me know if you have any questions and until next one bye
Info
Channel: Hamed Bahram
Views: 17,635
Rating: undefined out of 5
Keywords:
Id: e7bUYg7_hCI
Channel Id: undefined
Length: 22min 24sec (1344 seconds)
Published: Wed Jul 26 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.