
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
"Please login to view comments"
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
Complete source code for this lesson is available at
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
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
##Looks like we found a thief monkey By the way, I liked the trick how you reached till here. You have a good sense of humor. You will improve a lot if you join our course with this passion.
var
(function-scoped, outdated)let
(block-scoped, modern and recommended)const
(block-scoped, cannot be reassigned)_
, or $
let let = 5;
is invalid)myVar
and myvar
are different)string
, number
, boolean
, null
, undefined
, bigint
, symbol
Objects
, Arrays
, Functions
Subscribing gives you access to a brief, insightful summary of each lecture to stay on track.
00:00:02 Check out all of these pages we have created so far.
00:00:05 The homepage, we also have the communities page, the tags page, and even the collections and the most recent communities.
00:00:13 All of these pages have something in common.
00:00:16 They return some data, tags, profiles, or even questions themselves, but we need a way to further filter all of these pages.
00:00:26 And sure, we could go ahead and create a filter just for the users or a sort by popular, highest reputation or by moderators.
00:00:35 or we could implement another just for the tags.
00:00:39 This would be time-consuming as we would have to create standalone components and then tie them down with specific pages.
00:00:46 But if you think about it, if we already know that we'll need filters on all of these different pages, all of which have the same look and structure to
00:00:56 make things easier, let's create one reusable filter for all of these pages.
00:01:02 First, we can head over into Constants, and create a new constant called filters.ts.
00:01:10 Now, below this lesson, I'll give you a list of filters to paste right here.
00:01:16 It's just a list of a couple of different arrays.
00:01:19 And here, we're just defining what we want to filter.
00:01:23 Of course, feel free to play with this, modify it, or change it entirely.
00:01:27 The idea is to match these values with the values we have already implemented the logic for within our server actions.
00:01:35 So if you want to make sure that everything works, keep it as it is and try to understand it.
00:01:39 Or if you want to change it, you can totally do that, but then you'll have to head over into the question action, and you'll also have to rename the sort
00:01:48 and filtering criteria right here.
00:01:51 So with that in mind, what we're defining here is just a list of different filters that we're going to map through, such as the newest,
00:01:59 popular, unanswered, and recommended for the homepage filters.
00:02:03 For the answers, it can be newest, older, popular.
00:02:07 For tags, it can be from A to Z, maybe recent, popular.
00:02:12 In most cases, it is newest, oldest, popular with some other additions.
00:02:16 So now that we have those filters that we can easily map over, let's go ahead and install a ShadCN component that we'll use to make the filters happen.
00:02:25 It'll of course be a ShadCN select component.
00:02:28 It is super simple.
00:02:29 You click it and you can select a category.
00:02:32 So let's install it using the CLI by copying this command.
00:02:36 and pasting it right inside of here in our second terminal, mpx, shazian at latest, add select, press Y to install it, and say whatever you want,
00:02:48 either use force or use legacy peer depths, either way is fine.
00:02:53 Great.
00:02:53 So with that in mind, we now have this filter component installed, and we can create a new filter component within which we'll use the Schatzian filter.
00:03:03 So let's create a new filter within components, filters, and I'll call it common filter.dsx.
00:03:12 Run RAFCE.
00:03:14 And to see how this comment filter will look like, let's use it within one of the pages.
00:03:19 Maybe we can start with the home page, so that is root page.tsx.
00:03:24 This one right here.
00:03:26 If you notice, right below, we already have some home filters here.
00:03:31 But these ones only work on desktop.
00:03:34 But if I collapse the screen, you'll notice that they disappear on mobile.
00:03:38 So we'll keep using these home filters on desktop, but we'll use the common filters on the smaller screens.
00:03:44 Only on the homepage we have those two extra filters.
00:03:47 On all the other pages, you'll notice that we have none.
00:03:50 So the common filter will be everywhere, whereas the homepage will also have the two additional ones.
00:03:55 So, right here within the page, let's head over into our second section that currently has a margin top of 11, and let's add some additional class names
00:04:04 such as flex, justify-between, this is to make sure that both filters work well together, a gap of 5, a max smalldevices flex-call and on smalldevices items-center.
00:04:19 Within it, we're showing the search.
00:04:22 And right below the search, we'll also render the common filter component as a self-closing component.
00:04:30 And I'll pass to it filters equal to home page filters coming from constants filters.
00:04:38 And I'll also pass some other classes to make it work within this specific layout, such as the min h of 56 pixels.
00:04:46 I found that value to work the best.
00:04:48 And on small devices, min w of 180 pixels.
00:04:54 And we can also provide some container classes.
00:04:57 I'll make it hidden, as well as on Mac's medium devices, I'll make it flex.
00:05:02 This should now be enough to go into that component and to start implementing it.
00:05:06 Since we'll be seeing it on the small screen, I'll put my browser on the right side, and you can see the comment filter appear right here.
00:05:13 So let's start developing it by first destructuring the props we're passing into it.
00:05:18 such as the filters, the other classes, which we can by default set to an empty string, and container classes, which by default will be set to an empty
00:05:28 string as well.
00:05:29 And all of these together are of type props, which we can define the interface for right here.
00:05:36 An interface of props, where we have the filters that'll be of an object type.
00:05:43 And within it, we'll have a name equal to string and the value of a string as well.
00:05:50 Specifically, filters will be array of those values.
00:05:53 So you can specify that here.
00:05:55 Another way to create this would be to create a type or another interface called filter.
00:06:03 And then specify that a filter has a name and a value.
00:06:06 And then you can use this interface of filter right here and say that filters is of a type filter array, whatever you prefer.
00:06:15 And then we can also have other classes of a type string and container classes optional of a type string.
00:06:22 There we go.
00:06:23 So now right at the top, we need to extract the search params.
00:06:28 But this will be a bit different than extracting the URL params on the community page.
00:06:33 Remember that one where we simply used search params await search params right here.
00:06:40 While that is a super convenient way to get something out of the URL query, it is only possible to do that if a page is server rendered.
00:06:49 But of course, our filters will be client rendered because we have to make some kind of interaction.
00:06:55 So I'll add a use client directive at the top, and this allows us to extract URL search params like how we did it within the community page.
00:07:05 So in this case, we can first get access to the router functionality by saying use router, and then of course, importing that use router from next router.
00:07:16 But to get to the search params, you can say const.
00:07:19 SearchParams is equal to useSearchParams coming from NextNavigation.
00:07:25 So it is as simple as before, just now using a hook because we're in a client rendered component.
00:07:31 And look at me, I made a rookie mistake.
00:07:33 The useRouter was supposed to come from NextNavigation as well, not the NextRouter.
00:07:39 So if I fix this, I believe we should be good.
00:07:43 Great.
00:07:44 So how do we actually extract specific values from the search params?
00:07:49 Well, you just do it like this.
00:07:51 const and then you define a variable like params filter is equal to search params.get and then you take out the name of that variable.
00:08:00 So the thing is, the same as before, if you had a question mark, filter is equal to test.
00:08:06 And if you destructured it just like this and try to maybe render that param filter there, you should be able to see the test value that we just specified.
00:08:16 Perfect.
00:08:17 So we're successfully reading the values from the URL query or search params on the client rendered components as well.
00:08:24 Great.
00:08:24 Now, of course, we'll need some kind of a function that will handle the update of those params once we click on filters.
00:08:31 So I'll say const handle update params is equal to a callback function that accepts the value we're clicking on of a type string,
00:08:42 and we can do some logic that'll handle it.
00:08:45 But before we focus on the logic, let's actually focus on how those filters are going to look like.
00:08:51 We can do that by giving this div a class name.
00:08:56 And I'll make it into a CN class name by first making it a relative, and then defining the container classes that we're passing through props.
00:09:06 Within it, I'll define a select component, which we installed from ShadCN.
00:09:11 So we have access to it through dot dot slash UI forward slash select.
00:09:16 And it wants us to pass an on value change prop.
00:09:20 which will be equal to a Colbeck function, where we get the value.
00:09:26 And then we simply pass that value into the handle update params function.
00:09:31 And when you're calling a function like this, where you have a value and a value here, there's a shorthand for that.
00:09:36 And that is to just pass a function declaration itself.
00:09:39 No need to specify the params.
00:09:41 The second thing we're going to pass is a default value, which will be equal to params filter or undefined.
00:09:50 So if there is already some filter selected, we want to select it.
00:09:54 Next, within the Select, there is something known as a Select Trigger, which is also coming from UI Select.
00:10:01 This Select Trigger will contain a div That'll have a class name equal to line dash clamp dash one flex dash one and text dash left.
00:10:16 And within it, we can render something known as a select value coming from UI select, which is going to be self-closing.
00:10:26 And we can pass a placeholder to it, which is going to say select a filter.
00:10:32 There we go.
00:10:33 So now you can see a very simple filter component here, but of course now our job is to make it look better and of course to make it actually work.
00:10:42 So first things first, let's style the select trigger by giving it a class name equal to, it'll be dynamic CN class names where We will later on pass all
00:10:55 of the other classes into it to make it look a bit nicer, but we'll also pass some default styles that will always be there,
00:11:02 such as a body of regular no focus.
00:11:07 That'll remove that ugly border light dash border background dash light 800 underscore dark 300 text dash dark 500 underscore light 700 border.
00:11:23 padding X of 5 and padding Y of 2.5. Okay.
00:11:29 It's already looking better.
00:11:30 Let's also give it an area label equal to filter options so that people with screen readers can also read it.
00:11:38 And now we can go below the select trigger and we can render the select content.
00:11:44 So here's where you show the actual options.
00:11:47 Within select content, I'll render something known as a select group.
00:11:51 And within it, I will map through our filters coming from constants filters.
00:11:57 So it'll be filters.map where we get each individual item or filter.
00:12:03 And for each item, we'll return a select item coming from uiselect that'll have a key equal to item.value.
00:12:14 and it'll have a value of item.value, and we'll render that item's name.
00:12:20 So now you can see newest, popular, unanswered, recommended, they all appear right here, and you can kind of click to expand it.
00:12:29 Doesn't it look quite good, right?
00:12:30 Well, the problem is that I didn't really use the right imports.
00:12:35 See, I imported select content and select group from Radix, and I imported the rest from dot dot slash UI select.
00:12:43 Which, sure, is a component from ChatCN, but it's not the right one.
00:12:48 So what we need to do instead is import all of these components from add forward slash components, forward slash UI, forward slash select.
00:12:57 This is the right way to import it, but this on its own was not the problem.
00:13:02 The problem was that I auto-imported these components from Radix instead from Schatz Yen.
00:13:07 So if I put those two right here and remove the other imports, you'll notice that now we actually have a nice looking filter drop down.
00:13:15 This is looking good enough for me right now.
00:13:18 So let's go ahead and code out the function that'll actually update the filters.
00:13:23 We can do that by first forming a new URL that we want to replace our current one with.
00:13:30 And it'll be equal to the call of our form URL query utility function to which we need to pass an object containing the params equal to search params .toString,
00:13:44 so we pass over the entire current params.
00:13:47 We also pass the key which we want to update, which is the filter, and we need to pass a value that we want to update it to.
00:13:55 And this form URL query will simply spit out a new URL and then we can push to it by using the router.push new URL and want to set the scroll to be set
00:14:07 to false.
00:14:09 As in this case, we're just filtering, we want to remain at the current scroll, not scroll to the top of the page.
00:14:14 So if we do this on the homepage, you won't be able to see it, at least not on desktop, but on mobile devices, you now have this filter that allows you
00:14:23 to filter by unanswered, newest, recommended, popular, and so on.
00:14:29 So as you can see, just by implementing this component and by applying those filters to the URL query, Our homepage takes a look at that query right here
00:14:42 through the search programs and checks whether there are some filters.
00:14:46 If there are some filters, we pass them over into the getQuestionsServer action and based off of those filters, we can then return the valid posts.
00:14:56 Pretty cool stuff, right?
00:14:57 We have built a system that communicates the front-end click to the backend interface without having to touch the backend at all.
00:15:05 we just had to engineer it beforehand in a proper way to accommodate future changes.
00:15:11 Not as easy as it sounds, I know, but you get the idea.
00:15:15 If you can already envision that at one point, you will need to implement pagination or you'll need to implement filtering or sorting,
00:15:22 which if you're given a design, you'll already see those front-end elements on there, then you can already code it out into the backend and then just modify
00:15:30 the URL query which will then be passed over into the server action, returning to you sorted or filtered data.
00:15:39 I think this is pretty cool.
00:15:40 And just another one of those reasons of why you're watching this course instead of many other courses available out there.
00:15:47 We talk about the URL search params, the optimizations, how Next.js works under the hood and more.
00:15:53 And that's basically what we do on JS Mastery Pro.
00:15:56 If so far you only have access to the ultimate Next.js course, well, that's amazing.
00:16:00 That's the best one we have done so far.
00:16:02 But the goal with JavaScript Mastery in the future is to create so many more of these professional grade courses.
00:16:10 Of course, Next.js is at the top of our list right now.
00:16:13 But we'll also create full learning paths that you can go over and learn everything you need to get hired.
00:16:20 All of it available within your dashboard.
00:16:22 So if you haven't already, go ahead and check out our elite and pro plans on the membership page to get cheaper access to other upcoming courses.
00:16:30 If you decide to do that, that's absolutely amazing.
00:16:33 And I thank you for being a part of JavaScript Mastery.
00:16:36 If not, I still thank you for joining us on this Next.js journey.
00:16:40 We are about 75% into the full course and I hope you're enjoying it.
00:16:45 So let's go ahead and commit the updates for this lesson.
00:16:49 I'll say something like create filter component, commit and sync.
00:16:53 And in the next one, we'll be able to simply integrate all of those filters on all of the other pages.
00:17:00 So let's do that next.