
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.
Complete source code available till this point of lesson is available at
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 reusable LocalSearchBar component in Next.js. The session emphasizes the importance of user interface (UI) design before diving into functionality, and demonstrates how to handle search queries while effectively managing the URL state. We also introduce debouncing techniques to optimize search input handling.
00:00:02 To create our local search, you first need to notice that it's used in a lot of different places.
00:00:08 I mean, just check this out.
00:00:09 It's used right here on the homepage.
00:00:12 Then you can see it right here on the global search as well.
00:00:16 After that, again, it still remains in the global search, but it's also going to appear on pages like all users, as well as tags and hey,
00:00:24 even jobs.
00:00:25 So this is a perfect example of a component that has to be made completely reusable, so that it can match any scenario we put it in.
00:00:33 So, to get started creating the LocalSearchBar component, let's head over to Components, create a new folder, and I'll call it Search.
00:00:43 And within the Search folder, create a new component called LocalSearch.tsx.
00:00:53 Run RAFCE.
00:00:54 and then let's import it right within our homepage.
00:00:57 You already get the drill, right, of how we create a simple component, and then we immediately import it so we can see it,
00:01:05 and then once we do see it, we can dive right into it and start implementing it.
00:01:09 So let's develop the UI first, and let me give you a quick real-world example of how this might look like in your workplace.
00:01:17 you might start developing the functionality first and then not care about the UI at all.
00:01:23 For example, focusing on search queries, database calls, and so on, and then just have a basic HTML5 input that does the action.
00:01:32 or what you might do is first focus on the UI and then later on hook it up with the functionality.
00:01:40 Both of these options are totally okay.
00:01:43 And what we'll be doing in this case is a mix of two.
00:01:46 As you have noticed for sign-in and sign-up pages, we did do the UI, but then we actually hooked it up with OAuth, but then we actually hooked it up with
00:01:55 NextAuth and GitHub and Google providers.
00:01:57 We didn't do the form, and that's for a reason.
00:02:00 We first want to have a bit of a UI on the homepage, and then we'll dive into the functionality of allowing us to ask a question,
00:02:08 filter through those questions, and so much more.
00:02:11 but I prefer to have the UI that would allow us to do that, because then we can visually see what's happening.
00:02:17 So, starting off with the local search component.
00:02:20 So, starting off with this local search, let's first create a div, and this div will have a class name equal to background-light800 underscore dark gradient.
00:02:36 I don't think we've had this one before.
00:02:38 We can also give it a property of flex, min-h-56 pixels, grow, items-center, gap of 4, rounded-10 pixels, and a padding X of 4 to give it some breathing
00:02:56 room on left and right.
00:02:58 If I save this, we have something that resembles the search.
00:03:02 Right below that, we can render an input.
00:03:05 And this input is of course going to come from UI input.
00:03:09 And we can pass a type equal to text to it with a placeholder equal to, let's do search for now.
00:03:19 We also need to pass the value of this input, which is going to be just the default search.
00:03:25 value for now.
00:03:26 We also need to pass it an onChange, which is going to be a callback function where we get the event, and then we set the value of the search to that event,
00:03:34 but we don't yet have the handler, right?
00:03:37 So are we going to define the handler here, like a function that handles that search, or are we going to define it somewhere else?
00:03:45 We have to be very careful with thinking of how we approach it.
00:03:48 For now, I'll just leave this onChange as a blank function, like this, so we can decide what we want to do with it later on.
00:03:56 And of course, since we're using an input here, we'll have to turn this into a useClient component.
00:04:01 So right at the top, we can say useClient.
00:04:03 Okay, good.
00:04:05 Let's also style this input by giving it a class name of paragraph dash regular.
00:04:12 No focus to remove that ugly outline that we typically see.
00:04:15 Placeholder text dash dark 400 underscore light 700 border dash none.
00:04:23 There we go.
00:04:24 That's much better.
00:04:25 Shadow dash none and outline dash none.
00:04:28 All of these are going to play a role into making it a bit more natural.
00:04:31 And for now, we can leave the search value actually empty because we have no way of modifying it.
00:04:36 And if we go back to the design, and specifically if we focus on the homepage, which is right here, you can see that we have an icon on the left side.
00:04:45 Search for questions here.
00:04:46 So let's go ahead and add that icon.
00:04:49 We can do that before the input.
00:04:52 By rendering an image coming from next image, it's going to have a source equal to, let's do forward slash icons, forward slash search dot SVG.
00:05:04 Then we must also give it a width of about 24, a height of 24, an alt tag of search.
00:05:14 And we can give it a class name of cursor dash pointer.
00:05:19 If we save this, you can now see this great magnifying glass.
00:05:23 Great.
00:05:23 But now the question is, how are we going to make this reusable so we can use it across different places and modify its value across different pages?
00:05:33 Well, for that, we can pass different props to it.
00:05:35 And once again, this is a recurring theme.
00:05:38 Whenever you want to have a component that changes, that changes what it does depending on where it's shown.
00:05:44 Well, that's the only thing that makes sense, right?
00:05:47 Here, you're rendering it within a specific context.
00:05:50 In this case, it's being rendered within the context of the homepage.
00:05:54 So, it needs to have additional information on what it has to do.
00:05:59 For that reason, let's actually pass it some props.
00:06:02 The first thing that I'll pass it is going to be an IMG src, an image source for the icon.
00:06:09 So we can say forward slash icons forward slash search dot svg.
00:06:14 Next, we can pass it a placeholder equal to search questions dot dot dot because sometimes we might want to search tags or users or something else.
00:06:26 And then depending on the context where it's being shown, you can also pass it some other classes, like additional classes that you want to render only
00:06:34 for this specific variant of the local search.
00:06:38 In this case, I'll give it flex one so it can extend if it needs to.
00:06:41 Also, this search is going to be one of the primary things that will be handling the state management of our application.
00:06:49 It'll have to update the URL to modify the search query.
00:06:53 So it has to know where it is.
00:06:55 So for that reason, I'll give it a route.
00:06:58 In this case, it is on the homepage.
00:07:00 So I'll give it a route of just forward slash.
00:07:02 Now, if I go into the local search, I can accept all of those props.
00:07:07 So let's destructure the route, the IMG source.
00:07:12 the placeholder, and the other classes.
00:07:15 And we can specify the types of these by saying props, and then we can define the interface of props right here above, where the route will be a string,
00:07:25 image source will be a string, placeholder will be a string, other classes will be optional, and also of a type string.
00:07:32 So now we can add these additional classes right here, by rendering this as a template string.
00:07:38 There we go.
00:07:39 And we can just add other classes if need be.
00:07:44 Also, we can modify the placeholder.
00:07:47 So right here, we can render the placeholder and let's not forget about the image source right here.
00:07:52 So we can say IMG source.
00:07:55 So we can render different kinds of icons right here.
00:07:57 But now the biggest question is, how are we going to deal with the value and the on-change of this search and actually make it affect the page we're currently
00:08:05 viewing and its contents?
00:08:07 Well, let me show you.
00:08:08 Right here at the top of the local search, we can say const search params.
00:08:14 And make that equal to use search params coming from next navigation.
00:08:20 We can actually use the use search params because we are in a client component.
00:08:25 So hooks are allowed here.
00:08:28 Next, we're going to get the query from the search params by saying const query is equal to search params that get query.
00:08:36 And if a query doesn't exist, we can set it to an empty string.
00:08:39 Now that we have the query, we can create a new use state field that I'll call search and set.
00:08:47 search, which at the start will be set to a query.
00:08:53 So if a query is nothing, it'll be an empty string.
00:08:55 But if a query exists, it'll just populate it.
00:08:58 Now we can use the search right here as the value of the input.
00:09:02 So we can say search.
00:09:04 And now that I look at it, search is also a verb.
00:09:07 So it might be a bit better to call it a search query and set search query.
00:09:14 Great.
00:09:15 We can modify the value.
00:09:17 And on change we can get the event and then say set search query to set it with E.target.value.
00:09:26 So now we can actually type into it.
00:09:28 But we cannot yet submit it, right?
00:09:30 If you type something or click something, it's not modifying the URL, it's not doing anything.
00:09:36 Before I teach you how we'll submit it, first I want to show you that it actually works.
00:09:41 you can actually test it out by manually modifying the URL query by saying question mark query is equal to and then you can type any kind of search term
00:09:52 right here like let's say really hard react.js question And if you press Enter, you'll notice that it gets populated right here based on the URL query.
00:10:05 This is great.
00:10:07 But now, we'll have to do the real deal.
00:10:10 We'll have to implement the URL state management.
00:10:13 Remember the URL state management module?
00:10:16 Well, now is your chance to put things to practice.
00:10:19 To make our life a bit easier, we'll be using a query string library.
00:10:24 It is a super simple and very light library that just makes it easier to work with URL queries.
00:10:31 Like if you say location.search is going to give you the search query params part.
00:10:37 Or if you parse it, you're going to get a nice object out of it.
00:10:41 Could you do all of this by using manual JavaScript?
00:10:44 Sure you could, but it's a bit easier like this.
00:10:46 You get .parse, .stringify, and a couple of other useful methods.
00:10:53 So let's install it by heading over to our terminal and running npm install query-string.
00:11:02 Since we'll be using this query string library in a couple of different places, I want to put its code over to lib-utils.
00:11:10 Or let's even create a new utility file just for what it will do.
00:11:15 So we can call it url.ts.
00:11:19 Inside of here, we'll create two functions const form URL query is going to be equal to just the regular arrow function.
00:11:31 And another one will be const remove keys from query.
00:11:37 And I think we talked a bit about this at the end of the URL state management module.
00:11:41 The form URL query function will update URL query parameters with a new value.
00:11:47 So you want to pass a key and a value to it, and it's just going to add it to the URL.
00:11:52 That's it.
00:11:53 It doesn't do anything else.
00:11:55 So right here as params, we'll accept a single object where we get the params, a key, and the value.
00:12:02 And we get the params because we want to know the existing params that it has so we can append the new key and value to it.
00:12:08 So let's get access to the current URL by saying const current URL is equal to QS as in query string.
00:12:17 And we actually have to import this.
00:12:19 So let's say import QS from query string like this.
00:12:25 I'm going to zoom it in a bit so you can see better.
00:12:28 Next, we'll say qs.parse and we're gonna pass the params.
00:12:33 Not parseUrl, just parse in this case.
00:12:37 And it might actually be a good idea to know what we're parsing, right?
00:12:40 So for that reason, I'll first show you how we can call this function.
00:12:44 So let's go ahead and export both of these functions.
00:12:48 And now we can use them within our local search.
00:12:50 I'll create a new use effect right here.
00:12:54 And this useEffect will run whenever the search changes.
00:12:58 So let's add a dependency array and add the search query right within it.
00:13:03 So whenever we change the search query, this function will be recalled.
00:13:07 What do we want to do then?
00:13:09 Well, we want to check if a search query exists.
00:13:13 So if search query, in that case, we want to form a new URL containing that new search query.
00:13:22 So we can say const new URL is equal to form URL query coming from lib URL.
00:13:30 And now we know what it accepts.
00:13:32 It accepts the existing params.
00:13:35 So let's pass it the params.
00:13:37 And those are going to be equal to searchParams.toString.
00:13:43 Nothing special yet, right?
00:13:45 We're grabbing the search params, we're stringifying them, and passing them to form URL query.
00:13:51 But before that, let me actually show you how the searchParams.String looks like.
00:13:57 Let's actually render it right here as a piece of text within our input.
00:14:01 So I'll just render search params.toString.
00:14:05 And yes, this is how it looks like.
00:14:07 Query is equal to really hard React.js question, which is our search term.
00:14:12 So that's it.
00:14:13 That's the only thing we're passing into the form URL query.
00:14:16 What the parse functionality from query string will do is it'll actually parse it into an object.
00:14:22 So the response of this will be an object where we have a query equal to really hard reacts.js question.
00:14:30 That makes sense, right?
00:14:32 We also want to pass in a key and a value.
00:14:36 So let's say a key is equal to query and a value is going to be equal to the search query.
00:14:44 We have the params to be able to notice what the current query is because maybe some filters were already there.
00:14:50 So it wouldn't just say query is equal to something.
00:14:53 it would say filter is equal to new or filter is equal to upcoming.
00:14:58 So we must not lose the other params.
00:15:01 That's why we want to first stringify them and pass them over.
00:15:03 And then we want to specify which new one we want to add and which new value we want to add.
00:15:09 And also, even if we don't have any other inputs, we still need to specify the current state of the query input.
00:15:17 Like, as you're typing, the query will first be equal to r, and then re, and then rea, and then the words really.
00:15:26 So, we first need to contain all of those values, and then update it.
00:15:30 So, how do we update the value using this utility function?
00:15:33 We'll say, current URL, which is an object, and then we'll add a key within it equal to the value.
00:15:40 Once we have it, we want to return a queryString.stringifyURL to which we can pass additional options of URL is equal to window.location.pathname,
00:15:56 and then we want to append this query, which is the current URL.
00:16:00 And I guess a better name for this would be a query string.
00:16:04 So we're simply taking the base URL, taking the current query string, updating it with a new key and value, which we're appending to the query string,
00:16:14 and then simply appending it onto the URL and forming a new URL.
00:16:19 Let's also define the type of these props as URL query params.
00:16:25 And that's going to be an interface URL query params.
00:16:29 where we're going to have a params of string, a key of string, and then a value of a string.
00:16:35 Great.
00:16:36 So now we know that we're passing these new values.
00:16:38 And what are we going to do with this new URL?
00:16:41 Well, we'll simply define a new router at the top by saying const router is equal to use router coming from next router.
00:16:50 And then we'll use that router to push by saying router.push to the new URL.
00:16:58 And we're going to set the scroll to be equal to false.
00:17:02 Because in some cases, we don't need to scroll to the top.
00:17:04 And this use router is coming from Next Navigation and not from Next Router.
00:17:10 This is a very common mistake that happens and you might experience some issues.
00:17:15 because some code editors or IDEs tend to use the NextRouter functionality, but instead it should be coming from NextNavigation.
00:17:24 And if you do that, that's good.
00:17:26 Now you can see that we have a squiggly line right here, complaining that this use effect wants some additional dependencies,
00:17:34 such as the router.
00:17:36 We can also pass a route.
00:17:37 So if we change the route from home to tags, we want to be able to reload this function.
00:17:42 And we can also pass the search perhaps.
00:17:46 So whenever any of these functionalities change, we want to be able to recall the use effect.
00:17:52 If you reload, the error should be gone.
00:17:55 And now we can focus on the case where we don't have a search query.
00:17:59 So let's add an else to this if, meaning if we completely emptied it out, if we cleared out whatever is in the input.
00:18:07 We do want to check though if path name is equal to the route we're currently on.
00:18:14 So the path name is the current URL and the route is the route that we're passing right here from the home page or from any other page.
00:18:23 So we first want to make sure that they match.
00:18:25 For that reason, I'll say const pathName is equal to use pathName coming from nextNavigation.
00:18:33 And we can also add the path name right here to the dependency array.
00:18:37 Now, if that is true, and if we don't have anything in the input, we still want to be able to form a new URL, but this time we want to remove the keys
00:18:47 from the query instead of add them, because our input is completely empty.
00:18:52 So for that reason, let's create this removeKeysFromQuery function.
00:18:58 And to do it, I will actually just duplicate this function as it's fairly similar.
00:19:04 I'll rename it to remove keys from query or we can say URL query.
00:19:12 We get the query string and this time we need to pass into the function the keys that we want to remove.
00:19:20 So same as before, we call it remove keys from URL query.
00:19:26 We pass in the existing params, which is equal to search params that to string.
00:19:31 And then we pass in the keys to remove.
00:19:34 And in this case, we simply want to remove a query because we cleared up our input.
00:19:40 So now we get only the params and the keys to remove, which means that we have to create a new interface for this one.
00:19:51 Not the URL query params, but rather remove URL query params, which I will define right here at the top.
00:20:00 By duplicating this one, changing its name to remove URL query params.
00:20:04 And instead of key and value, we get keys to remove, which is an array of strings.
00:20:11 Now we can actually map over that array by saying keys to remove dot for each key.
00:20:22 We want to perform an action and that action will simply be delete query string key.
00:20:29 Okay, pretty simple.
00:20:32 So we're deleting it.
00:20:33 After that, we form a new stringified URL.
00:20:37 to which we pass the URL and the query, we'll need to add an additional options object that's going to be skip null is equal to true.
00:20:47 Sometimes they notice that if we remove a filter and if instead of setting it to an empty string, it gets set to null, then we would end up having something
00:20:56 like filter is equal to null in the URL.
00:21:00 But if you run this, it'll actually clear it.
00:21:03 So now, let's go back to local search.
00:21:05 And what are we going to do once we delete the keys from the URL?
00:21:09 Can you guess?
00:21:11 Well, we'll simply return it by saying router.push new URL, scroll, false.
00:21:17 Great.
00:21:18 Now, let's try it out together.
00:21:20 First, I will remove this SearchParams2 string because we no longer need it in the input.
00:21:25 Next, we can see that this is our search, and we can try typing something.
00:21:29 or even removing things.
00:21:31 But this time, we want to track how our URL bar behaves.
00:21:35 That's the thing that we've been working on, right?
00:21:37 So if you type something like React, or just R for that matter, notice how immediately the question mark query appears and it is equal to R at the top.
00:21:50 So if I continue typing React, you can see how a query gets updated.
00:21:54 This is great.
00:21:56 And since we're using this query string package, it automatically serializes it to be URL safe.
00:22:02 So if I add a space, that's equal to the %20 character, or like arrows or something.
00:22:09 You can see it all very nicely works.
00:22:12 And the beauty of that is that if you type something, And you can now copy this URL and share it with your friend in the other browser,
00:22:21 and the search will actually get populated for them.
00:22:24 But not only the search, the search doesn't matter, right?
00:22:27 What matters is that this search will actually be applied to the fetch request of the database, which fetches all of the questions or the data.
00:22:35 So that means that your friend or whoever you're sending this website to will have access to all the same data, cards, or content that you want them to have.
00:22:45 So great, we have just implemented URL state management.
00:22:49 But of course, to really call it state management, we actually need to do something with that data.
00:22:55 For now, we're just modifying it.
00:22:57 But before we go ahead and put it to use, I'm still not done with optimizing it.
00:23:01 Can you spot the issue with this?
00:23:04 Like, whenever I type, right now nothing is happening, but imagine that we are doing a refetch to our database.
00:23:11 And I type and type and I delete and I type and I delete and I type again.
00:23:18 What's happening?
00:23:19 We're making additional requests to the database.
00:23:22 We're overwhelming it.
00:23:24 We are just racking up bills and expenses for whoever is hosting that database.
00:23:29 So to fix that, good developers use a tactic called debounce, or specifically a delay debounce, which allows you to only send a search that allows you
00:23:41 to only send a request when a user stops typing for some time.
00:23:46 How can we implement it?
00:23:48 Well, it's pretty straightforward.
00:23:50 We're going to use the built in JavaScript functionalities.
00:23:52 I will create a new function called const delay debounce.
00:23:58 fn, as in function, and I will use the setTimeout functionality from JavaScript, which allows you to create a new function block.
00:24:08 What setTimeout does is it schedules execution of a one-time callback after a delay in milliseconds.
00:24:17 So the first thing that you pass is the actual function, the callback function, and the second parameter is going to be a delay in milliseconds.
00:24:26 So I'm going to pass it, And I'm going to set it to, let's do 1000, which stands for 1000 milliseconds, or that is one second.
00:24:36 So if I add a console log right here, or as a matter of fact, let me add an alert.
00:24:42 That's going to be a bit more intrusive.
00:24:44 And I'll say debounced.
00:24:46 And now we can call this function delayDebounceFn whenever this use effect runs.
00:24:53 And you can see how we get debounced.
00:24:55 And in this case, it actually looks like that it doesn't want me to call it.
00:24:59 It's saying delayDebounceTimeout has no call signature.
00:25:03 So what do you need to do in React?
00:25:05 Whenever you use a timeout in a use effect, you want to make sure to put it at the end and say return callback function clearTimeout like this.
00:25:18 And then you wrap the function declaration, not a function call.
00:25:22 So no parentheses, just the function declaration, which actually clears it.
00:25:26 And in this case, I don't even think that we need to mock this with alert to show you how it works.
00:25:32 What we can do is actually just put this entire search query right within it.
00:25:38 So I'll just put this up.
00:25:41 And now whatever code is in here will automatically be debounced.
00:25:46 What does that mean?
00:25:47 Well, let me show you.
00:25:48 If I type a letter A, that it takes one second for it to appear.
00:25:53 If I type B, that's another second.
00:25:55 You can see how it takes one second to update the URL.
00:25:59 I know that the text right here is a bit small, but hopefully you can see it.
00:26:02 But now if I type CD fast, you can notice that they both went together.
00:26:07 How?
00:26:07 Why did it not take two seconds for those letters to appear?
00:26:11 Well, that's because as long as you're typing, so I'm typing right now, it's not gonna do anything, as long as you don't stop for one second.
00:26:22 When you stop for one second, it'll consider that it is done, and it'll send over that request.
00:26:28 So, check this out.
00:26:29 I just send over hundreds and hundreds of characters, but we haven't yet made a single request to the backend.
00:26:37 whereas in the previous situation we would have already sent maybe a thousand requests for data to come back by this time.
00:26:47 And I click, it is there in a second.
00:26:50 Since developers type a bit faster, we don't need to give them a second between each character, we can give them maybe 300 milliseconds.
00:26:57 So this way, if you type React, you can see it immediately appears.
00:27:01 But maybe now you want to add something like React CSS mistake, you can see it gets sent.
00:27:08 We still minimize the number of requests, but our app is still super performant.
00:27:13 In fact, it is more performant than if we didn't delay it because we don't have to hold the weight of making all of these requests.
00:27:21 In simple words, debouncing is a way to control how often a function runs.
00:27:27 especially when users are typing a lot.
00:27:29 In search boxes, it helps us by waiting a short time after the user stops typing before sending a request.
00:27:37 This makes the search faster and reduces unnecessary load on the server.
00:27:42 This was such a great lesson, hasn't it?
00:27:45 I hope that everything that you've learned in the theory of the state management URL clicked, because now you got to experience it in person,
00:27:54 by yourself, on a real practical example that we're implementing within our application.
00:27:59 As a matter of fact, I want to take it a step further, and I want to show to you how this would actually filter the cards.
00:28:06 So let's say that we have different questions in our homepage.
00:28:09 Those questions will appear right here.
00:28:11 Instead of displaying them as p tags, let's actually create a new object called const questions is equal to an array where we have an object of an underscore
00:28:25 ID of one.
00:28:27 We can also have a title of the question, something like how to learn React.
00:28:33 I want to learn React.
00:28:34 Can anyone help me?
00:28:35 This was written by GitHub Copilot, by the way.
00:28:38 Each question can then also have a list of tags or an array of tags.
00:28:43 So that's going to be an array where each tag has an underscore ID and a name, such as React.
00:28:49 Maybe it's going to be JavaScript and so on.
00:28:52 Next, it's also going to have an author.
00:28:55 So who created that question?
00:28:57 And the author will also have an underscore ID, name, and maybe even image.
00:29:02 But let's not worry about that for now.
00:29:05 I'll also remove the created ad.
00:29:06 There we go.
00:29:07 You can see how Prettier automatically stylized this for me.
00:29:11 And each question will also have a number of upvotes.
00:29:15 So how many people found it helpful.
00:29:17 The number of answers.
00:29:19 It's going to have the number of views.
00:29:21 like 100, and it's going to have a created at, which is going to be a new date, and we can just leave it like this.
00:29:30 So this is a question.
00:29:33 We can for now duplicate this question and just have one more below.
00:29:37 The second question is how to learn JavaScript.
00:29:41 Let's do it that way.
00:29:42 Now we can map over those questions by going down and saying questions.map, where we go over our question.
00:29:52 And for each question, we can render an h1 that's going to render the question.title.
00:29:59 Looks like I didn't close it properly.
00:30:01 Now it's good.
00:30:02 And let's also give it a key, since we're mapping over it, of question dot underscore ID.
00:30:08 Oh, and looks like we forgot to change the key.
00:30:10 This is pretty cool that now Next.js or React are giving us a warning about the same keys.
00:30:15 So the second one will have an ID of 2. And you can see it now.
00:30:20 How to learn React and how to learn JavaScript.
00:30:24 Now, how can we use this search to actually filter out these questions?
00:30:29 Well, let me show you.
00:30:30 We'll again use something that is completely new to Next.js.
00:30:35 If I head over to the top of the homepage, I will just collapse these questions and actually I'll put them outside of the component since they're static
00:30:44 right now and soon enough we'll update them with the real data coming straight from our database.
00:30:50 But for now, the question is, how can we actually extract the current search term from the URL so we can filter out through our database fetch data?
00:31:00 Well, for that, we can destructure search params.
00:31:05 While we're here, let's also specify its type, and we can call it search params.
00:31:11 So let's define an interface of search params, and we can make that equal to A promise.
00:31:19 Yep, this is new.
00:31:21 In newer versions of Next.js, you now have to await search params.
00:31:25 So we can see that this promise will return an object where key of a type string contains a specific string value.
00:31:35 What do I mean by that?
00:31:36 String, string.
00:31:37 Well, I mean something like query.
00:31:40 is equal to react.
00:31:42 That's basically it.
00:31:43 So now that we have the search params, how do we extract the query from it?
00:31:47 Well, we can say const query is equal to await search params.
00:31:53 And now what?
00:31:54 Now we can use the query to modify the fetch from our database.
00:31:58 If we had a real fetch that would look something like this, consData is equal to await Axios.get or something where we get the questions where we pass
00:32:10 the data of search or query into it.
00:32:14 So you can get real data based on that query.
00:32:17 At this point in the course, we don't yet have the real data.
00:32:20 We'll do that very, very soon.
00:32:22 But still, I want to show you how this would work in a real example.
00:32:26 So what we can do is say const filtered questions is equal to questions.filter.
00:32:35 And we want to get each question that question.title.toLowerCase includes the query.to lowercase.
00:32:47 And to make sure that the query is there and it doesn't break our application, we can add a question mark right here.
00:32:53 Perfect.
00:32:54 And finally, we can render the filtered questions.
00:32:57 I'll also hide this home filter for now so we can have a clearer view of what's happening.
00:33:02 And while we expected to see all of the questions initially, since the search bar is empty, there are no questions there.
00:33:09 That's because query could be undefined at the start.
00:33:12 So if it is undefined or falsy, we can actually give it a default value of an empty string.
00:33:19 So that way the includes will actually work if it's an empty string.
00:33:23 This is a pretty cool JavaScript feature that not a lot of people know about, and I like using it.
00:33:30 So now let's put it to the test.
00:33:32 If I search for react, you can see only react.
00:33:36 And if you search for JavaScript, you can only see JavaScript.
00:33:39 Let's actually expand this to full view.
00:33:41 So you can see the URL bar.
00:33:43 There we go.
00:33:43 Query JavaScript, query react.
00:33:46 And thanks to our remove URL keys from query, if we delete it, plain URL, both questions right here.
00:33:53 This was such a great lesson, wasn't it?
00:33:55 You got a chance to practice the URL state management in Next.js that you learned a lot about in our theory lessons about state management in Next.js.
00:34:04 But now you got a chance to actually put it to the test within the application you're building.
00:34:10 I mean, this is already looking great with the left sidebar and the right sidebar as well.
00:34:14 That collapses to create some more space for the main content on tablet devices.
00:34:19 And then of course, mobile works seamlessly.
00:34:22 In Next.js, there's no Zastan needed or no Redux, no React context.
00:34:28 You can manage everything using the good old URL bar.
00:34:31 And you also learn how to debounce your inputs to make them more efficient.
00:34:35 Everything is also completely secured because we're using the query string package, so we can be sure that it's going to properly parse and stringify it.
00:34:43 So great work so far, and this definitely deserves a commit.
00:34:47 That way you can properly track everything on GitHub.
00:34:51 So I'll say implement local search bar.
00:34:57 I'll commit it, sync it, and if you head over to GitHub, go to commits.
00:35:02 As you know, you can see the full commit history and you can explore exactly which changes we implemented in this commit.
00:35:09 That way, whenever you're developing some of your own custom applications, and your application needs to use a search, which most of them will,
00:35:18 you will know how to do it properly using best practices.
00:35:21 And if you need to check out the entire code base at this specific point in time, you can do that easily.
00:35:27 And just press the dot on your keyboard and it'll open it up right in your browser.
00:35:31 I mean, with all of those skills under your tool belt, you already are a great developer.
00:35:36 Being able to see a Figma design, think about the architecture of how you're going to approach building it, then very quickly build those components,
00:35:45 implement the logic in the best way possible, and then ship it to the clients, that's what you're built to do as a great Next.js developer.
00:35:52 So, great job in this one.
00:35:54 Take a bit of a break, and I'll see you in the next lesson.