In this chapter, I want to build a feature that we have seemingly forgot to implement, and that's the search filter. So if you go to localhost, you will notice that our search filter does nothing at all. And while I have no doubt that if you have watched the tutorial this far, you can definitely build this yourself, perhaps you might have already done it, but still I'm going to show you how I would do it. So let's start with use product filters hook and search params file. So I'm on my master branch, I'm up to date and I have BunrunDev running.
So the first thing we're going to do is we're going to go inside of source, Let's go inside of modules and let me find where we keep it. I think it's inside of products. We have used products filters and we have search params. So open up both of these. Let me try and separate them like this.
And we're going to add search. And search will simply be a string. So we can do parse as string here. We already have this imported. And let's go ahead and pass in dot with options clear on default set to true and with default empty string and I think we don't need to execute the parse as string great, now let's copy this and let's paste it here So you should have it both in your search params and in your use product filters.
Great. Now that we have this we can mark that as completed. Now let's go to our products get many procedure so products server procedures get many and in here let's add the search to be a string nullable and optional like this you can move it down here with the rest of the filters. So now we have to choose how to query. And from payload documentation, you can see that for querying search, they have two options you might want to use.
Like and contains. Like is case insensitive and all words must be present in any order. Basically, that's the rule. So case insensitive and any order. So it's much more intuitive for users.
Whereas contains is case insensitive as well, but I believe that this works on the specific order of words that you write. So I think that like is a better solution to use and will give a better experience. So let's go ahead and use get many here. So we are going to focus on querying the name field for the products. It doesn't make sense to query the description because the description is a rich text element.
There we go. So I'm going to go after the sort. Let's actually go all the way down here, right? After the input, we can even do after category. Let's add it here just before we query.
So if input search, let's go ahead and add where name and let's add like input dot search like that. So now we should be able to query our elements by search. So let's see if we've done this correctly. So without doing any new modifications now, you should be able to do the following. You should be able to add search.
And then for example, let me search for, I don't know, the word daily. If I try this, there we go, you can see that only daily appears. So our filter already works, right? There's nothing more that we have to do here, except of course connect it to the actual search input component. So let's see the flow, let's see how this works.
Instead of our home UI, we have search filters And it has no props, which means that we can go directly inside of search input here. And we can go ahead and grab our filters and set filters here. Use product filters. Make sure to import this from modules. And we are specifically going to focus on modifying the search filter.
So let me find the input here and I will just collapse the items like this. So I'm going to pass in the value, and I'm going to make the value filters.search. And on change, I'm going to grab the event, and I will do event. I will do set filters, specifically the search event target value like this. So let me go ahead and refresh this and you can see that now it auto populates to daily.
But if I go ahead and change this to 10 for example, you will see that it auto-populates to 10. So just like that we have implemented for example let's search for ebook. There we go You can see that it loads ebook. So it was that easy to implement the search filter. Obviously, now we have a question of adding debounce, right?
So if you go ahead and look in the network tab, it causes a lot of requests to type absolutely anything in here. So there's a couple of options here. We can implement a simple debounce hook and add it specifically here in the search input. But one thing that I perhaps want to do instead of that is go inside of my Products, hooks, use product filters. And I think that in here we might have some options like shallow and throttle milliseconds, for example, like this.
And I think that this might actually it's not debounce but it's throttle so I think that it works in a similar way for example let's try 10k doesn't look too good I'm going to be honest So perhaps this is not how it should be used. So let's quickly visit the NUX documentation to see. So instead of the docs, I actually found an open issue on NUX where they discuss about the bouncing URL updates. And you can actually see that they are making a lot of progress here. So depending on when you're watching this, maybe it will be merged because it looks like they are very close to merging this.
But it is not as simple as it seems. So as of right now, no, Nuxt does not have built-in option to debounce. I'm not sure why my throttle here is not doing anything at all. Perhaps I don't understand throttle myself. So I'm just going to remove that and what I'm going to do is I'm just going to show you how you can implement a very quick debounce yourself.
Of course, if you want to, you know, you can use any package, use debounce or something like that. So I'm going to add a field here, const searchValue, setSearchValue from useState with the default value of filters.search or an empty string. Actually, I don't think there's a need for the fallback here because search should be an empty string by default because we added with default empty string here. So now what we're gonna do inside of useEffect is const timeoutId to be setTimeout And I'm just going to debounce for half a second. And then I will set filters search, search value.
And I will return here, basically unmount, and I will clear timeout, timeout ID. And inside of here we can pass the search value and set filters. And now all that we have to do is modify the value here to be search value and in here we simply have to change this to set search value event target value. So I'm not sure if this is the best way to do it, but I think this is a super simple debounce that you can test out. So let's try it by looking at the network tab.
Let's refresh this. Super simple debounce. There we go. So you can see that only after I finished typing for half a second, it now fires an event. So yeah, if you want to, here's a super simple way to clear the search value.
And that's exactly how we implemented our search filter. And you can see that when we remove everything, the URL is completely clear. Excellent. So let's go ahead and mark this as completed and this as completed. And we can now push to GitHub.
Since we have this deployed, what I'm gonna do is I'm just going to directly push like this. So 32 search filter. And let's just do git push directly. And once you do git push on the master without branching this will automatically trigger a new deployment and by doing that you have also deployed to Vercel. Amazing, amazing job.
So after deploying my search filter changes, my deployment actually failed and perhaps yours will fail as well. And the message is a little bit cryptic. It is telling us that useSearchParams should be wrapped in a suspense boundary at page pricing. So why does it say that? I made sure to run bun run build locally just to confirm that I'm getting the same error locally and I am which is a good thing.
This will make it much easier to develop on. So I searched for use search params and it's nowhere to be found in our project. But it's obviously related to use product filters. So this is what I suggest we do now. I suggest we find where we use the search input here, and we've wrapped that inside of suspense from React.
And let's go ahead and give this a fallback of search. I'm not sure if I can put search input inside now. So maybe I'm going to do export const. Actually I don't think we have to do anything. I don't think you even have to add a fallback.
So what I'm going to do is I'm just going to do bond run build and see if this maybe fixes it. Because now use product filters, which is the equivalent of use search params is wrapped in a suspense and the reason that this is telling us that it's in the pricing page I think that's just a coincidence It is because we are using this in a layout file, right? So we are using it inside of app here, home, layout. This is where we are using it. And while it has a suspense, it looks like it needs to have a lower suspense here.
Let's see. So now it's simply telling me that it should be wrapped in a suspense boundary some other page. So I'm not sure if our suspense wrapping actually made any difference. So I'm just going to pause the video and look at how I have to implement this. I think the reason it's still happening is because of the search filters skeleton so that kind of makes sense We just wrapped the search input into suspense, but that initially didn't make sense to me because in our layout, we've wrapped the entire search filters into suspense.
So what's going on here? Well, what's going on is that we use search input in our search filters skeleton, which we then use here outside of suspense. So That's the issue. So this is how we are going to fix this. You can remove the suspense wrap around the search input, and you can remove this from here.
Since Search Filters is safely wrapped in suspense, what you can do here is simply transfer loading of the filters from search input component inside of the search filters component. So use product filters, add the import here and we're simply going to add the default value to the search input component. So let's do it like that. Default value is going to be filters search and on change is going to accept the value and call setFilters and set the search to be the new value. As simple as that.
So we only have the default value here and the rest will be controlled inside. So obviously this can be made in a kind of a nicer way. But I think for now, the goal is to preserve the functionality and to fix the deployment issue. So let's see. We have added use product filters here.
We have added on change. And let's go inside of search input and let's add the default value here or you know if you want to you can just call it the value like this but This is kind of incorrect because technically, yeah, I would rather we call this default value because we want to stay true to what it is. So it is an optional string. Let's see if this still works. It does.
And in here on change is a string, sorry, value string void. As simple as that. And now here we have the default value and we have on change. We can now remove use product filters from here. There we go.
And inside of here we are going to pass the default value. And then inside of here instead of set filters we just call the on change which is the new search value here. And let's just see. So this is string or undefined. For this, okay, so let's do it like this.
There we go. And the onChange here is because we mark this as useClient. So you can remove this as useClient and then the warning will go away. The reason you can remove this is because we use it inside of a client component. And now in here, we need to add onChange.
So I think that now we are officially preserving this. And yeah, make the onChange optional. So then you have to call the onChange optionally. And there we go. No more errors.
And before I try running the app, I'm going to try building the app first just to see whether I understood this correctly. So basically, you can search throughout your app for use product filters, and you will see that in all of these places where you use it, you actually have to wrap those things inside of suspenses. So the reason it doesn't appear in other places is simply because I assume we are either using it in a dynamic page or we are not using it in a layout. I think The problem is mostly with these static pages and using of the useSearchParams. I think that if you use useSearchParams inside of something that is recognized as a dynamic page, it won't cause that error.
There we go. We fixed it, right? So I was correct. Okay. But if you want to, you can go throughout your project, right?
If this is still causing you problems, you can of course go throughout your project and look for all the places where you use use product filters. Though I think that majority of them are in one way or another wrapped in some kind of suspense here or if not wrapped in a suspense well in that case they are at least in a dynamic component so that's why it's not a problem, right? If it's causing you problems, feel free to just wrap these inside of suspenses like this. Because apparently, you should do that. So I'm not going to do that simply because my builds are passing and there's no reason for me to do so.
So what we did is we moved the importing of useProductFilters from inside of the search input to adding it to the search filters component, which is wrapped inside of Suspense. And then we can safely use the SearchInput component in the skeleton. So the skeleton was actually the problematic build here. So now I'm just going to do bun run dev, just to confirm that we can still use our application here so let me just try it out and let's try 30 days there we go everything still works fine so now I'm gonna go ahead and commit this and push to GitHub, which will cause another deployment, hopefully this time passing. So git add, git commit, 32, search, filters, fix, and git push.
And once you do git push here, you should see a new deployment appear any second. Let's see. There we go. So I'm going to pause and we're going to see if this one is successful. But since our local git build works, there's no reason for the remote one to fail.
But yeah, interesting bug. It was fun to debug this. It was because of the usage in the skeleton, which is then used outside of suspense. Quite hard to track. And here we go, a successful deployment, meaning that it was officially the fix.
So obviously we're going to try it here, 10 minutes. Let's see. And there we go, our search is officially working. Amazing, amazing job. So yes, now we officially resolved the search filters and we fixed that interesting bug with suspense.
So one more thing, so if you're using used product filters, search it like this. If you're getting similar errors you can always search them like this and then you will see the component that should potentially be wrapped inside of suspense. You can see that not all of them need that But these ones which are in the layout seem to have caused some problems, so be careful and at least you now know how to fix it. It needs to be wrapped in a suspense.