Fix Shortlist Icon0:00
Okay, so we are able to like and shortlist our puppies. Next, let's tackle the search filtering mechanism so that we can search for puppies by character traits. So we're going to focus on this component here in this lesson, but I just wanna fix up a tiny thing on the short list. Don't worry, it's really quick. But because we had this H2 collapse, I forgot to update the SVG here and that's the little hard here. So we wanna change that to use the lucid react hard icon.
to update the SVG here and that's the little hard here. So we wanna change that to use the Lucid React hard icon. And I'll do this real quick, hard and we'll go with copilot suggestion. Looks like it works. All right, so I'm not quite sure why I had the inline-block class here. And also this size-6 class here is not really needed because the default size we've seen is 24 pixels by 24 pixels. Uh, for Lucid React icons, I can remove that class
Plan Search State0:52
by 24 pixels. Uh, for Lucid React icons, I can remove that class and we are going to delete the entire SVG. And we are good with a quick short list aside. Okay, let's dive into the search filtering. The first thing we need to work out is what sort of state we want and where that state should live. We have the one search field here to search for a characterTrait. And so I feel that we are going
for a character trait. And so I feel that we are going to need a searchQueryString as a piece of state. And then I imagine that our puppiesList needs to be aware of that search. Uh, just like we were filtering the puppies by the shortlisted one. We also need to filter the puppies by the search string matching the character trait. The shortlist itself doesn't really need
by the search string matching the character trait. The shortlist itself doesn't really need to know anything about the search query, but definitely the puppies list needs to know. And so to me it feels like the place where that state should live is the same as where the liked status lives because this is where we have that search component and also the puppies list. So let's do just that. We are going to create a new piece
Pass Search Props1:46
and also the puppies list. So let's do just that. We are going to create a new piece of state a searchQuery string, and then we're going to pass it to both the search and the puppies list components. Alright, const searchQuery and setSearchQuery is going to be a state value and set and it'll default to an empty string. And also to verify that it works, I will set the default value to Hello.
And also to verify that it works, I will set the default value to Hello. Alright, and next, let's pass these states down to first the Search component. So searchQuery equals searchQuery and set searchQuery. Set searchQuery. Alright, and we have type errors, but we'll fix that inside the Search component because here we are going to receive the searchQuery and set searchQuery.
because here we are going to receive the searchQuery and set searchQuery. So we set the searchQuery to a string and the state setter, remember we want to be a bit more react specific. So we'll go dispatch setState action and then the string inside of here. Okay. And as I tend to do, we are going to have a pre tag just to json_encode the value of searchQuery just to check that it works.
to have a pret tag just to json_encode the value of $searchQuery just to check that it works and indeed it does. Alright, so let me delete the stringify demo. And what we wanna do next is synchronize the $searchQuery with the $searchField here. Technically the $searchInput is a form field and we are going to talk about forms in React later when we do a lesson on this, uh, create new Puppy form. But for now we're going to treat this field as just an input.
Build Controlled Input3:10
do a lesson on this, uh, create new puppy form. But for now we're going to treat this field as just an input and we're going to turn this input into what's called a controlled component. So React has this concept of controlled versus uncontrolled components when it comes to elements like form elements. And so when it's uncontrolled, it kind of means that the browser handles the value and then on submit or on blur on certain events you do something.
that the browser handles the value and then on submit or on blur on certain events you do something. But here we want to be a little bit more aggressive and take control over that component. So we are going to assign our state value, our searchQuery to that component, and then let's react control the value at all times. Right now, this input field is free form. I can type in it freely and it's uncontrolled. But if I scroll down to the input element here,
I can type in it freely and it's uncontrolled. But if I scroll down to the input element here, I am now going to turn it into a controlled component by setting its value to our searchQuery state. And because we've set the default value to hello, I'm expecting the input field and yep, it does to say hello, but now I cannot type. I am typing really loud. You can probably hear that in the microphone, but I cannot change the value of this component.
You can probably hear that in the microphone, but I cannot change the value of this component. It's tethered to hello, because this is our state value. The dev tools should warn us about this. And yet you can see it's telling me to decide between using a controlled or uncontrolled input element. But here we've already made the decision that we want a controlled component. But to make it a usable, viable control component, it needs to have a value, but also the ability
But to make it a usable, viable control component, it needs to have a value, but also the ability to change the value somehow. So like when we used a button, we had an onClick event listener with the input's type, we can have onKeyDown, onKeyUp, onBlur, onChange. And here we're going to use onChange. So I've set the value to the searchQuery. And then on change we are going to have a function that is going to receive the event.
And then on change we are going to have a function that is going to receive the event. And let's start with a console.log. console.log. And we are going to take the event.target.value. So unchanged fires every time there's an attempt to change the value inside the input field. So we still have the value of hello. And if I try to type another O after hello, you can see that it logged the second O. But if I type another O again or I type an L.
after hello, you can see that it logged the second O. But if I type another O again or I type an L or a K, you can see that it's always resets to hello because we haven't done anything to change the value, but at least we logging the events that targets that value. So what we need to do is take that event that targets that value and set the searchQuery state to that. So basically instead of logging this, we are going to call the setSearchQuery function and set it to events that targets that value.
to call the setSearchQuery function and set it to events that targets that value. And this time if I try to add OS to my hello, it works, I can delete the text and search for mother of pups or anything. But obviously nothing is wired up. But at least we are controlling our components input and we are controlling the searchQuery state value. So we are controlling and updating the value
So we are controlling and updating the value of the searchQuery from the search component. And now we can pass that searchQuery state to the puppies list. I'll add it to the start here. searchQuery equals searchQuery. All right, let's go start by updating the type. We need to also receive the searchQuery and I'll copy that here so I can paste it in the type.
Filter Puppies List6:26
We need to also receive the search query and I'll copy that here so I can paste it in the type and define it as a string. And if I scroll down to the place where we map over the puppies here, we're going to do something very similar to what we've done in the shortList. So just as a refresher, in the shortList, we have first filtered the puppies based on what's included in the liked array and then we mapped over them.
we have first filtered the puppies based on what's included in the liked array and then we mapped over them. So we're gonna do something very similar here. I'll move the map on its own line and before that we will filter. And for each pup looking at the ui, it says search for characterTrait. And that trait in question is the little sentence describing the pup. So we're going to use the includes function once again,
describing the pup. So we're going to use the includes function once again, and we're going to check if the popThatVibe, I almost forgot that we renamed it to Vibe, includes the searchQuery. Basically if the popThatVibe string has the searchQuery as a substring anywhere inside that string, then we are going to keep it. Otherwise we are going to filter it out and then we are going to map over what's left.
Otherwise we are going to filter it out and then we are going to map over what's left. Alright, and oops, we've got nothing. Ah, because we have the hello string. So let's try delete everything. You can see that it should work. So we have all the six Bs. And if I search for mother MO, uh oh, can you guess what happens here? Let me try again. MO doesn't work, but you can see that here I have an uppercase M.
Let me try again. MO doesn't work, but you can see that here I have an uppercase M. So if I search for uppercase, MOTH, uppercase E. Ah-huh. So the case sensitivity is the reason it's not working. And typically when someone does a search, you don't want them to have to match the exact casing, uppercase or lowercase. So we can basically standardize this by putting both sides of the comparison to lowercase. And we'll do the same for the search query, that's
of the comparison to lowercase. And we'll do the same for the search query, that's to lowercase. So we are essentially normalizing our search string to be all lowercase. And this time if I change the M to lowercase M, it's still going to work. Let's try chase. Good boy. Leah enjoys naps. It's working beautifully. So just like this, it looks like we've implemented our
It's working beautifully. So just like this, it looks like we've implemented our search filtering functionality, so we can now like and dislike puppies and we can also search for the trade. So let's say save the world here, I'll search for world. And here's Russ. Very cool stuff. So let's recap what we've done to make this work. Before we wrap up the video. First we identified what sort of state we need and where it should live.
First we identified what sort of state we need and where it should live. And because it's needed by the search field here and by the puppies list, we have decided to place that state in the main component. So we've created a searchQuery string for our state, and then we passed it to the search component and the puppies list. In the search component, we use this searchQuery to turn our input into a controlled component,
In the search components, we use this search query to turn our input into a controlled component, which is hardwired to the search query. And then unchange, we update that value to the new value from the events that targets that value. This is how we change this value. And then in the puppies list, we consume only the search query. We don't need to set it from there. We use this search query to filter out the puppies.
We don't need to set it from there. We use this search query to filter out the puppies that do not pass the vibe check. But yes, we take the vibe of each puppy, we lowercase it to normalize it, and then we compare it with the search string. If that is included, we keep it, otherwise we filter it out. And so now our puppy list is only showing the cards for the puppies that match the search. It's all pretty simple and it all works great.
Add Reset and Focus9:54
for the puppies that match the search. It's all pretty simple and it all works great. So if we wonder who likes cheese, the answer is puppy. In the excitement of everything being so easy. I was about to wrap up this video, but I just realized we forgot to implement this resetSearch functionality right now when I click on this, nothing happens. What we do want to happen when clicking that button is the searchString to be reset.
What we do want to happen when clicking that button is the search string to be reset so all the puppies show and the user can start searching for something else. Alright, I'll give you five seconds to close your eyes and visualize how we're going to implement this. Can you see the solution? Okay, I am in the SearchComponent here, which is where we have the input field and we also have this button and oh my God, another SVG, let's delete that SVG.
where we have the input field and we also have this button and oh my God, another SVG, let's delete that SVG by using the Delete Lucid React component instead. And it looks like we are using no classes at all here, so I can get rid of that and it still seems to look the same. And so like I said earlier, yes, this is an input and yes, this could be a form and then form have a reset functionality. But here we just treat it as a single control component.
and then form have a reset functionality. But here we just treat it as a single control component and we can use that button to update the state accordingly. So we already receiving the setSearchQuery that we use inside the input to change the value. And well we have a button here and the button can have an onClick event listener. And here we can set the searchQuery to an empty string. That's pretty darn simple and that should do the trick.
to an empty string. That's pretty darn simple and that should do the trick. So let's try it. Cheese. And then I click the button and the search is reset and all the puppies show. Let's try one more time. Nap reset. It works. It works, yes. But can you think of a way to further improve the user experience here? Check this out. When a user searches for cheese and then resets the form to do another search, they have
Check this out. When a User searches for cheese and then resets the form to do another search, they have to go and click again in the field and search for nap and cancel it. But wouldn't it be cool if when the User clicks on the reset button, the form field is instantly focused once again? And you know what? We're going to implement that right now real quick. So one thing to understand and know is that the focus state
So one thing to understand and know is that the focus state technically belongs to the browser. It doesn't belong to React. So we need a way in React to kinda offload to the browser to take control of that focus state. And the way you can do this in React is by using what's called a ref for reference. So you've seen that you can use useState already, but you can use another thing called useRef.
So you've seen that you can use useState already, but you can use another thing called useRev. So let's have an identifier, const inputRev. And we are going to set this to useRev. And useRev is going to want a default value and we can pass null here. And then we're going to assign this inputRev to our input element. So here rev equals inputRev. So now this inputRev is basically our gateway,
So here rev equals inputRev. So now this inputRev is basically our gateway, our escape hatch from React to the DOM. And so here where we click the button, let's have console to have multiple statements. And I will also console.log the inputRev. So let's try to click that button and you'll see that our inputRef is an object that has a current property, which is the actual download on our dump tree.
that has a current property, which is the actual download on our dump tree. And so instead of logging this, what we can do on a click, just like copilot says, is to target this input ref and the inner current property. And then we can call the focus method on it, which should focus that input. So let's close the console and try mother. And then when I click this, I'm expecting the searchQuery to go empty and the focus to go back in the input field.
And then when I click this, I'm expecting the search query to go empty and the focus to go back in the input field so I can start searching right away. So click cheese, click nap. And by the way, I say click, but I can tap into the button and press the space bar or press the enter key and it's also gonna work. Very good boy. Alright, and this time, this concludes this lesson on control components.
Alright, and this time, this concludes this lesson on control components. In the next video, we are going to look at the new puppy form. And this time we're going to use uncontrolled components and see how we can work with longer forms in React.
