- Read Tutorial
- Watch Guide Video
What I want to do, and you may have seen this on other portfolios before, is I want to create a filtering process. I want to have links or buttons here at the top where I can click on one of those buttons and it'll actually auto filter what values are shown to the users.
I think that would be really neat so you could have your portfolio, you could have all these different types of projects, and then by the user being able to click one of those buttons it will filter in and out of what values that we're passing in. Now I will say we're only going to build about half of this feature, we're going to build it so it works, but it's not actually going to be the full implementation.
That's going to have to wait till we're working with our API because then we're going to have... the initial state isn't going to be hard coded, it's going to be coming in with real life data, so I'll show you what I mean when we get to that point.
But for right now we're just going to build the core functionality and it's gonna repeat and give us a little more practice on how to set state, and this one's going to be a little more dynamic, so we're going to be able to pass in the values, and have our function perform, and have a little more logic behind it.
So let's get started with that, we're going to get rid of this handle page title update because we're not going to be using that, and let's also get rid of the tag and the button, and then we can also get rid of where we're binding that and we're going to create a completely new function.
I'm going to call this handleFilter, and if you're curious on why I used this key word of handle in front of a lot of the custom functions, that is not necessary, but as you're gonna see as you go through more React documentation and you look at some of the best practices, whenever you have a click handler usually you want to name the function that is going to handle that, handle, or at least start with the word handle.
Part of the reason for that, it's just a convention, but you will see it in some of the most popular and most successful React applications. I like it a lot because it gives me a hint right away of knowing what that function is doing so it tells me that this is connected to a click handler and it helps me just kind of have a mental framework for understanding what that function's goal is.
With this handle filter function I want to pass in an argument, so we're going to see how we can pass arguments directly into these click handlers, and then from there have them give a little more dynamic behavior. Before we do anything else let's just bind that to the this
key word. I'm going to say this.handleFilter = this.handleFilter.bind(this)
.
Now that is really weird code, it doesn't matter how many times you see this, and it is one of the complaints that people do have with React is how you have to do this for each one of your custom functions that deal with events. But the more times you do it you'll eventually just get in the habit of it and you will remember what these key words are. It's always the this
keyword followed by a dot, and then the name of the custom function, and then you repeat that exact thing. So this.name of custom function.bind
and then you pass in (this)
, and that's all we're doing there.
So how are we going to filter this data? Well, we know that we're going to need to setState, so let's just start with that. I'm going to say this .setState, and so everything here is exactly just review. We know we call setState and we call this function whenever we want to update those state values, and we pass in the parens and then an object, so, so far everything is exactly the same as we've done before. Then from here we want to update our data values, this is exactly the same data that we have right here.
Now we're going to use a special function inside of JavaScript. This is just going to be pure vanilla JavaScript that is going to allow us to loop through and then select the items that we actually want to work with. Now I want to have this be category driven data, so we need to add a little more data to our object, so come up inside of each one of the objects and add a new key called Category.
This first one I'm going to call eCommerce
and you don't have to spell it the same for yours, but whatever you use for spelling is going to have to be exactly the same. If we do eCommerce here and I use the capital C for the second letter, if we use that again we have to make sure we're following the exact same convention.
Let's do category, and then we're going to do category again, and for this one I'll say Scheduling
, and then for the next one we're gonna do category, and this will be Enterprise
, and then last one category, let's make this one eCommerce
again, and make sure they line up perfectly.
portfolio-container.js
this.state = { pageTitle: "Welcome to my portfolio", data: [ { title: "Quip", category: "eCommerce" }, { title: "Eventbrite", category: "Scheduling" }, { title: "Ministry Safe", category: "Enterprise" }, { title: "SwingAway", category: "eCommerce" } ] };
The reason I'm doing this is because if we're wanting to filter data we need some way of picking out which elements we want versus which ones we don't. What I am envisioning is inside of the browser being able to have buttons and one might say eCommerce and another one will say scheduling, and I can click on those and this list will be updated automatically.
Let's switch back here, and so inside of our set state function what I'm going to do is I'm actually going to have another function running here. The way I can do this is inside of our data element we can call state. So I can say this.state, so I'm grabbing this exactly the same way that we grabbed the title for the page. I can say this.state.data
, and then I'm going to call the filter function.
The reason why I can call this, this is it's a different filter than we have right here. This is a filter that is going to allow us to iterate over a collection of data, and it happens to be called data right now, but it can work on any kind of array.
Now let's take, if you've never used the filter function or maybe you've only used it a few times, let's just take a quick look to see exactly how it is going to operate. I'm going to open up a JavaScript console session here and let's give ourselves a little bit of room and I'm going to create an array.
Let's say that I want to create an array of numbers, so it's just going to be one, two, three, and then one again. What I can do is loop over this array, now this is very similar to what map does, but where map builds a collection and it's just looping through and adding items on top of the stack.
What filter does is it allows us to pick and choose which items we either want or don't want. Let's say that we want to grab all of the 1's inside of this array. What I can do is let's store this in a variable, so I'm going to say const and then selected, you can call this anything you want, it's just a variable. Then from there, array. and we want to go with filter, and then just like we did with map, we're going to pass in an argument.
You can see here it's telling us it wants a callback function so the very first thing we're going to pass in is that function argument, just like map allowed us to have access to the value, filter's the same exact way. The first time it loops through, I'll just call it el for Element, and the very first time it loops through Element is going to be 1, next time it's gonna be 2, then 3, and then 1 again.
I'm gonna say el and then pass in some curly brackets, and I'll say return el, and then triple equals 1, end it. Oh, I had a little typo, you see where you need to also close off your parentheses. Let me just run that again, except this time I'm going to close it off, there we go.
Now if I call selected you can see that it has changed and now we have this new array and it's only pulling in the ones.
What filter does is it allows you to loop through the collection, you pass in a conditional. If that condition is true then it adds that entire element directly into wherever you're storing it, which in this case is this selected variable. Hopefully that gives you a little bit of an idea of what we're wanting to do here. I want to loop through this collection of names, and whenever it finds a category that we want to have it matched, then I want it to filter those items.
Let's now finish this implementation, I'm going to say data.filter
and then I can say item because we're still iterating over items just like we do with map, and then we're going to pass in the arrow function and then curly brackets. Now what I want to do is say return item.category
, so whenever the item category, so it's going to loop through, it's gonna say okay, the first one has a title of Quip and a category of eCommerce. Second one has a title of Eventbrite, category of Scheduling.
So when it loops through I'm going to ask it for it's category, I'm going to say if this is equal to the filter I want you to return this. Very similar to when we're looping through those four numbers and we said is the number equal to one? If it is add it to the collection, if not, then just ignore it and skip right over it.
In this case, instead of storing it in a variable we're actually setting state with it. Let's hit save here and then come down here and we're going to add these buttons, so let's come add our list of buttons. The very first one I want to be eCommerce and then let's create two more, so we have eCommerce, Scheduling, and then that third one was Enterprise.
What we need to do now is add our listener, our click listener. Now this is going to look a little bit different and the reason is because we need to pass in a custom argument. Remember that we're passing filter in and the way that we pass in a custom argument to a click listener is by saying onClick equals, but instead of just saying this.handleFilter like we did before, if we tried this, so if we passed in eCommerce just like this, this would not work.
<button onClick={this.handleFilter('eCommerce')}>eCommerce</button>
The reason why is it has to deal with how JavaScript manages functions that have parentheses. Whenever you have this type of syntax what would happen is the page would load and then JavaScript would immediately try to run this. So you'd get a bunch of errors, because you would get three functions that are all trying to update the state automatically.
What we need to do is create what's called an anonymous function. We're just going to say I want to store these parens, and then an arrow function, and now what this is going to do is it's not going to run automatically, it's going to be placed almost kinda in a holding pattern. The page is gonna load and then the functions are going to be ready, but they're not going to be called automatically.
We're going to do that for each one of these, and then the only difference is we're going to change what these values are. The first one's eCommerce, the next one was scheduling, and then the next one was enterprise. I'm going to hit save here and I believe this should be everything we need to get this working. Let's now come and see, I'll hit refresh just to be safe, you can see we have eCommerce, scheduling, and enterprise.
Now if I click on eCommerce, you can see it worked perfectly. It picked out our two items, our Quip and SwingAway those were the ones listed as eCommerce. Now this is where only half of the implementation is done, you'd expect in a normal application that you could click on eCommerce, and then if you clicked on scheduling you'd expect it to show the scheduling one, but that is not the case and I wanted to keep this in for a specific reason.
What is going on here is when I click eCommerce what it's doing is it is actually changing the state completely so it doesn't know any more about Eventbrite or about Ministry Safe. When we clicked eCommerce it went through and it only kept the eCommerce one, so state was updated and it had just thrown away these other items. To get them back obviously you can just hit refresh and we're back to our initial state.
If I click on Enterprise you can see we're back to Ministry Safe, hit refresh again, if I click on scheduling then it brings up the Eventbrite one. It is working perfectly for what we want it to do right now and eventually once we actually bring in live data then what we'll do is when these items fire they're actually going to be calling an API, and then bringing in the data so we're not going to have them hard coded the way that we have right now.
If you did want to hard code these values the best approach would be to store them inside of a function and then you would have some type of condition and handle filter where it reset it back to the full list of items. Instead of calling this.state.data, it would go through and it would reset it, and then you'd have your full list again. That's why it's not complete yet because eventually we're going to be pulling in the real data, which in a real life application that's what you'd be doing anyway, so that is how that works.
Hopefully that's starting to make a little bit more sense. Hopefully you're able to see how powerful set state is where you can manipulate the data in your application however you need to. You can create filters, you can add items, you can remove items, you can do all of that, and it is all, all of that data is contained inside of that single component.