
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 focus on the implementation of a filtering system within a home page component, following the earlier implementation of a search function. The objective is to create dynamic filters that allow for effective categorization of content based on various criteria.
useState
to manage which filter is active based on user interaction.00:00:02 Now that we've implemented the search, let's implement filtering.
00:00:06 I'll go to the components folder and create a new folder called filters and create a new component called home filter.
00:00:18 I'll run RAFCE.
00:00:21 I'll head over to the page in the root, which is our home page.
00:00:25 And where we have the home filter text, I will actually turn it into a home filter component.
00:00:32 So let's automatically import it.
00:00:35 and head into it.
00:00:36 Believe it or not, the Home Filter component will work very similarly to the Search component.
00:00:43 Think of this as your exercise of re-implementing what you implemented in the search to recap your knowledge.
00:00:49 First, let's define different filters that we'll have.
00:00:52 const home page filters, or we can call it just filters in this case, since we are already on the homepage, is going to be equal to an array of different objects.
00:01:05 Like name is all and value is all.
00:01:09 In this case, I'll call it newest and the value will be newest.
00:01:14 And we can repeat the same thing for something like popular.
00:01:20 And again, popular here.
00:01:22 Let's do it two more times.
00:01:24 One more time for unanswered.
00:01:26 Same thing right here as unanswered.
00:01:29 And finally, we'll have recommended.
00:01:31 So these are going to be questions specifically recommended for you by the algorithm.
00:01:38 Now that we have those filters, let's actually map over them to show different buttons for each one of these filters.
00:01:45 By saying filters dot map, where we map over each individual filter.
00:01:51 And for each one, we can return a button component coming from UI buttons.
00:01:58 Each button will of course render the filter dot name.
00:02:03 And since we're mapping over it, we have to give it a key equal to filter.name as well, since each filter is unique.
00:02:10 And would you look at that?
00:02:11 We have four nice looking buttons.
00:02:14 Now let's style this div by giving it a class name of margin top of 10. Let's hide those on small devices.
00:02:22 So we can say hidden, give it a flex dash wrap.
00:02:25 So we wrap them gap of three and in medium devices, we want to put flex so we can show them.
00:02:32 or actually maybe even on small devices, we have enough space to show them.
00:02:36 So if I expand this just a tiny bit, you can see that now we have enough space for the filters.
00:02:41 Next, let's give each button a class name, equal to body-medium, rounded-lg, padding x of 6, padding y of 3, capitalize,
00:02:57 and shadow-none.
00:03:01 And of course they haven't been applying because I misspelled the class name.
00:03:05 There we go.
00:03:06 Now this is a bit better.
00:03:08 I can expand it just a tiny bit more.
00:03:11 There we go.
00:03:12 Now to each one of these, we also want to give specific class names depending on if that filter is currently selected or not.
00:03:21 So let's create a new use state.
00:03:25 active and set active at the start equal to an empty string.
00:03:30 Import use state from react and turn this into a use client component considering that we are clicking the buttons.
00:03:38 And this has to be the same as with the search.
00:03:42 Each one of these clicks on these filters will change the URL bar.
00:03:46 So we actually have to fetch the value of the query string to know which one is currently selected or not.
00:03:52 For that, what are we going to use?
00:03:55 If you don't know, you can look into the local search bar.
00:03:59 But we're going to use search params.
00:04:02 So let's do just that.
00:04:04 Let's say const search params is equal to use search params.
00:04:11 And we can import this from next navigation.
00:04:13 We can then get access to filter params by saying they're equal to search params that get filter.
00:04:20 And we can set the use state to be equal to either filter params if they exist or empty.
00:04:27 Now that we have them, we'll be able to know which one is active.
00:04:30 And based on that, we can give specific class names.
00:04:34 So let's turn this into CN, which stands for class name, that's going to get all of these default classes.
00:04:41 So we can just put them in a template string.
00:04:43 And then as the second parameter to this, we can check if the active class is active for that specific filter.
00:04:51 So filter.value.
00:04:53 And if it is, we can return one string.
00:04:56 And if it's not, we can return another.
00:04:58 So what are we going to use for non-active filters?
00:05:01 Let's do a BG light of 800, text-light-500.
00:05:08 hover of BG light 800 on dark mode BG dark 300 on dark mode text dash light 500. And in dark mode, on hover, bgdark 300. There we go.
00:05:28 But what about the active ones?
00:05:31 Well, let's give it a bgprimary 100, text-primary 500. On hover, bgprimary 100. on dark bgdark 400, on dark text-primary 500, and on dark and hover bgdark 400. Okay,
00:05:57 so now as soon as we select one, when we implement the functionality to do so, you'll be able to see the active classes as well.
00:06:05 So how can we actually select one?
00:06:07 Do we have to add a use effect, same as what we have done here, and then track the changes in the filters?
00:06:15 What do you think?
00:06:15 Think about it and try to answer me in three, two, one.
00:06:20 No, we don't need a use effect because we can track click events.
00:06:25 So let's create a function const handle type click is equal to a function that accepts the filter that we're clicking on of a type string.
00:06:35 And for each one, it can set it as active.
00:06:37 So if there actually is a filter that we're clicking in that case, we can set active to be equal to the filter.
00:06:45 Else, if there is no filter, we can set active to be an empty string.
00:06:49 Now, if we head over to our buttons, we can actually give it an onClick property by saying onClick is a callback function,
00:06:59 or we call handleTypeClick where we pass in the filtered out value.
00:07:06 But if we click on these, they're going to seem active because they are right now as we're changing the state.
00:07:14 As you can see, set active filter.
00:07:17 But we're not actually changing the URL bar, which is the only thing we actually care about.
00:07:22 Not the state of the UI, but the general state of the application.
00:07:27 So how are we going to change the URL bar?
00:07:30 What do you think?
00:07:31 Once again, I'm going to give you a couple of seconds to think about it.
00:07:34 You can look into the search bar, maybe something useful here.
00:07:38 Or would this just work for search?
00:07:41 Well, no.
00:07:42 Check this out.
00:07:43 I can copy the place where we modified the form URL query for the search.
00:07:48 I'll paste it right here below set active.
00:07:50 I'll import form URL query.
00:07:52 Instead of changing the query, I'll change it to filter and the value will not be search query.
00:07:59 It'll be filter.toLowerCase.
00:08:03 And what do we do when we want to remove a filter?
00:08:07 Well, we already know that as well.
00:08:09 It is right here in the local search bar.
00:08:11 We call remove keys from URL query.
00:08:15 And we can paste it right here, import it from libutils.
00:08:20 And then at the end, so below both the if and the else, we need to use the router.push.
00:08:26 So right at the top, let's say const router is equal to use router from next router.
00:08:34 Oh, no, it's not next router.
00:08:35 Now you know where it is coming from.
00:08:37 It should be coming from next navigation, right?
00:08:41 So let's not make that mistake again.
00:08:45 And at the end, below the else, we can say router.push and we want to simply push to a new URL and we can pass a scroll is set to false as we don't want
00:08:58 to scroll to the top.
00:09:00 This new URL currently is defined in both of these if blocks.
00:09:04 So instead, let's actually create a new let new URL is equal to an empty string at the top, just so we have access to it within this scope right here.
00:09:16 So we can use it below, but instead of reinstantiate, but instead of setting it right here each time, we can just modify the value.
00:09:25 And now we have access to the new URL.
00:09:27 Now check this out.
00:09:28 If I click newest, filter newest.
00:09:32 I click on popular, filter popular, unanswered, recommended, and so on.
00:09:37 This is working perfectly.
00:09:40 Do we need to implement the debounce here?
00:09:43 What do you think?
00:09:44 Well, the answer is no, because the user will only click on one at a time.
00:09:48 And how can a user remove a filter once it's selected?
00:09:51 Like we can click on another, but can we remove all of them?
00:09:54 What do you think?
00:09:55 How would you implement that?
00:09:56 You can do it by switching these to if and else statements.
00:10:01 First, I'll check if filter is equal to the currently active filter.
00:10:07 If it is, then what we can do is clear things up.
00:10:11 So I will simply set active to nothing and remove keys from URL query.
00:10:16 And then I will put the set active into the else.
00:10:19 So if we're not clicking on the current one, that must mean that we're clicking on another one.
00:10:25 So we want to turn it on.
00:10:26 So I click popular or others, it still works, but I click again on the selected one and it gets unselected.
00:10:35 But as you can see in the URL bar, it still remained there.
00:10:39 That's because I forgot to change this remove keys from URL query.
00:10:43 Which key are we removing?
00:10:45 Well, this function is super reusable.
00:10:48 The only thing we have to do is change this to filter.
00:10:53 If we do that, click newest, it's there and click it.
00:10:57 It is gone.
00:10:58 Great work on implementing the filters.
00:11:01 And as you can see, it all starts coming into place.
00:11:04 Once you truly understand how search params, client and server components, and filtering works behind the scenes, it's just super easy to work with it.
00:11:13 And wait, how are we going to get access to the filter right here in our homepage?
00:11:18 Well, we can just extract it from the search for rams by saying filter.
00:11:22 Currently we have filters for newest, popular, unanswered, and recommended.
00:11:28 These are more so sorts than filters, but that's okay.
00:11:31 For the time being, I will comment them out and I'll create a name all value nothing.
00:11:39 Well, we don't really need it because if it's not clicked, that means that it's going to show all.
00:11:44 But let's do React and let's do JavaScript as well.
00:11:49 Okay.
00:11:50 And of course we have to change the values.
00:11:52 So this is going to be JavaScript and this one right here will be React.
00:11:57 If we do that and expand our browser, we now have React and JavaScript.
00:12:01 So how do we actually make these work with the filtering of the content?
00:12:07 We can go back to the page.
00:12:08 We can accept the filter.
00:12:11 make it equal to an empty string if it's not doing anything, and then we can further filter the questions.
00:12:16 Since this is very messy code right now, and we'll definitely remove it later on with proper API fetches from the database,
00:12:23 I'll just use GitHub co-pilot to do it for me.
00:12:25 I'll say command shift i or control shift i, select the code, And I'll say something like filter questions based on filters too.
00:12:38 There we go.
00:12:38 To filter the questions, it gave me this block of code, which I will simply insert.
00:12:44 There we go.
00:12:45 Let's see what it did.
00:12:46 It said questions.filter matches query.
00:12:50 Okay.
00:12:50 So it's matching for the title, but is it actually matching for the filter too?
00:12:55 Let's see, const matches filter.
00:12:58 question.category.
00:12:59 Oh no, I think it's going to be tags.
00:13:01 Okay, so question.tags, but tags is actually an array.
00:13:07 So if you want to make it work with that, we actually have to map over the tags.
00:13:11 But you know what?
00:13:11 For now, I'll just say tags zero, because the first one should actually be the one that matches.
00:13:17 For JavaScript, I'll set it to JavaScript.
00:13:21 And for React, it's already set to React.
00:13:24 So now I'll say tags 0, dot name, because a tag has a name, and then dot to lowercase.
00:13:32 So now if I save this and I select React, you can see it filters out React.
00:13:38 And if I unclick it, we can see both.
00:13:41 And here I can see just JavaScript.
00:13:43 This is pretty cool, right?
00:13:44 So we can now do it based both on search or how to learn, which finds both.
00:13:50 And then I can further filter it by a filter.
00:13:54 Check this out.
00:13:55 A filter and a query working together.
00:13:58 So this means that what we're working on is completely extensible.
00:14:03 Great job implementing filters.
00:14:05 Let's say implement home filters, commit, sync, and we are ready for the next lesson.