3.3 Adding Functionality to Components
One of the purposes of components is to compartmentalize functionality. In this lesson, you'll get a little taste of how useful it is to encapsulate functionality.
1.Introduction2 lessons, 06:11
2.Getting Started2 lessons, 14:39
3.Building the Hangman Game5 lessons, 39:23
4.Working With Data4 lessons, 32:39
5.Conclusion1 lesson, 00:56
3.3 Adding Functionality to Components
A few lessons ago, I mentioned that React applications are built by combining components together. And in this lesson you're going to start to see, why. Because, ultimately, what we want to do when creating a component is encapsulating the functionality of that component. So that that component is responsible for doing its job. For example, we are inside of the letter grid component and we are generating the spans that are going to contain the letters, and that's all well and good. But we also need some extra functionality. For example, we don't want to show these letters by default, we want just blank there so that the user doesn't see what word it is that we're supposed to guess. So we need to either show or hide a letter based upon the other letters that the user has guessed. And we can include all of that functionality directly right here inside of letter grid. But I think it would be better to start to compartmentalize our application so that this letter component that we are going to write in this lesson is just going to be responsible to responding to the data that's passed to it. For example, we'll have a letter here, that's going to be our component. And the letter needs to know what letter it's going to be working with. So we will have a value prop, where we will assign the given letter. But then, we also need to know whether or not to show this value to the user. So we can have an isShown prop. And let's start with true just that whenever we implement this, we can see that everything's working. Then later on we can come back and add this to false. So that this letter component is going to be rather simple, but it is going to be doing one very important thing, and that is either showing or hiding the letter from the user. So, let's just implement that. Now, as far as stylistically is concerned, a lot of times you will see components that have multiple props are defined like this, inside of JSX. It might take a little bit of time to get used to this style, but this is typically what we do. We put each individual prop or even if it's just a normal attribute, we will put that on its own line. Just to make it a little bit easier to read. So, we want this letter component. So, let's create a new file, we'll call it letter.js, let's go ahead and import that inside of the letter grid. So, we will import letter from, and that was simply letter. And then we're going to start off just like all of the other components to where we are going to export a function. And we have two props, we have the value, and we have that isShown prop. And for right now we will just simply return our span element that we had before. And we will have the value and we'll leave that for now, let's go to the browser. Let's do a refresh and make sure that we are getting the same results as we got before. It looks like we are, let's inspect, and voila, we are. All right, so now let's add the functionality for incorporating this isShown. So the first thing we need is kind of the default value of what we are going to output to the user. So I'm just going to create this local variable called output. And it's going to be just empty. Well, it's not empty it has a space in it. And then we will check the value of isShown. If that is true, then we will set output equal to the provided letter. And then instead of outputting value, we will output our output. So if we go back to the browser, we should still see our word, and that's fine. However, let's go back to the letter grid. Let's change the value that we are passing to isShown, let's pass false. Now this should hide the wording, and it does. If we take a look at the markup, we can drill on down to the spans. The spans are still there, but there is just an empty space in between the opening and closing tags. So we now have a letter component that is responsible for one thing, either showing or hiding the value, the letter that we are working with. Now, it's not responsible for determining whether or not that letter should be shown. That responsibility should go to the letter grid because, well, that just makes sense. If we look at the game board, the game board itself shouldn't be determining whether or not an individual letter should be shown. We have a letter grid and the letter grid should be doing that. It is responsible for generating the letter components, it should also be responsible for determining if that letter should be shown. Now the game board could keep track of the letters that have been guessed. So, we could have a guessedLetters prop on our letter grid. And this would be just an array that contains the letters that have been guessed. Now the letters need to be lowercase because we don't have to worry about if something is uppercase or lowercase. If we just normalize everything as lowercase, then it just makes our lives so much easier. So, for right now, we're going to hard code this array. Later on it will, of course, be dynamic. But let's implement this guessedLetters prop. So, instead of our letter grid, we just need to add that to our props D structure. And then we will use this inside of the callback that we used for the map method. So we're going to change this callback function to a multi-line function, so that we can have some logic in here. We, of course, will still need to return our letter component. But before that return statement, we will determine whether or not if we should show the letter. So, let's just have a variable called isShown. And we can do this, we can use the guessedLetters. And we are going to search the guessedLetters for the letter that we are currently working with. So, we can simply use indexOf, we will pass in the letter, but remember that our guessedLetters are all lowercase. So we should normalize this to lowercase. And if one is found, then the index is going to be greater than one. So, if it's found then we, of course, want to show it. And so, we will pass isShown, all the way to the letter component. So just by doing this we should see the results. We see R and a. If we wanted to add another letter there, we could simply add t. So, we would see R, a, and t, Rat, that was not intentional. But let's do a letter that's not there, j. Of course, we're not gonna see j because, well, j is not in the word React. But let's also do this, let's change the secret word so that we have a word that has multiple letters, or multiple same letters like TutsPlus. There's multiple T's, multiple S's, multiple U's. So now, of course, we don't see any results. If we go back to the game board and change this, so that let's just have t. We should see two T's in the game board, and we do. Now, there's one other thing, if we look at the console, first of all, you're going to see that we have this error up here. And really it's a warning, it's not an error. But it says, each child in the list should have a unique key prop. Now we are getting this because we are iterating over an array, and we are generating a lot of letter components, right? Here inside of letter grid, and this is what it's complaining about. Whenever you iterate and generate a lot of components, behind the scenes, React needs to know how to access these individual components. And so what it needs is called a key. The key isn't something that we work with, it's just something that is internal to React, and it needs to be unique for the array that we are creating of letter components. So, what we could do is very simple, we could use the index of the given letter that we are working with. That way, it will be unique for each individual letter component. So, by adding this key, we will refresh the page, we will see that the warning is still there. And that's because I used the string value of index, as opposed to using the actual value of index. So, if we go back, let's refresh that warning is going to go away. And there are some others, it doesn't like that I've used anonymous functions, but we're going to ignore that. So, in the next lesson, we are going to start developing the button grid, which is going to go inside of our game board. There's going to be some similarities, but ultimately the functionality will be very different.