Alright guys it's time to apply everything that we've learned so far to our keeper app project and 1
make it actually have some functionality. 2
If you head over to the course resources and fork your own copy of the keeper part 3 3
starting project, you'll notice that the challenge instructions are very simple. 4
All we want to do is to be able to add notes and delete notes from our keeper app. 5
This is the final functionality that you're looking for. When we add a note with a new title 6
and when we click the Add button it clears those inputs and pushes a new note into our array of notes. 7
So if we added another, then you can see they will just keep getting added alongside each other. 8
The second part of the challenge is to be able to click on the delete button and for that note to be 9
removed from the stack of notes here. 10
Now even though it sounds simple, there's only two steps each of these steps will involve quite a few 11
things that you've learned along the way. 12
If you want to get started with the challenge and you think you can tackle it already, then go ahead 13
and pause the video and give it a go 14
now. If you want to watch him break down the challenge into smaller pieces so that you can tackle it 15
one by one which is obviously a lot easier, then feel free to continue listening. 16
All right. 17
So the first part of implementing the add Note functionality is probably going to involve some sort of 18
state management right? 19
We're probably going to have to create a constant that keeps track of the title and content. 20
In addition, when the new note whether it's title or content gets created, we're probably going to want to 21
pass the new note back to the app component. Ad then maybe in the app component we'll have some sort 22
of array right? Which we can add the new note to an array and this array is probably going to be something 23
with states which you can set state and you can read it. And then we can take that array and render a 24
separate Note components for each item in the array. 25
And these sub steps should together create the implement add Note functionality. 26
Now the second step where we want to delete notes, we're probably going to need some sort of way of getting 27
a callback from the Note component that's going to trigger a delete function. The delete function is 28
probably going to live in the App.jsx. 29
And in this case, we're probably going to want to use the filter function to filter out the item that 30
needs deletion. 31
So you're going to have to think about how to pass an id over to the Note component so that when you 32
trigger the delete function, you can pass it back to the app component in order to identify the Note 33
that needs to be removed from the array. 34
So this is the broken down version of the challenge and I recommend giving it a go and seeing how you 35
get on. If you get stuck 36
then come back and watch me go through the solution step by step and then maybe that'll help you get 37
unstuck and you can continue with the rest of the steps of the challenge. 38
All right. 39
So pause the video now and try to complete this challenge. 40
All right. 41
The first thing we're going to address is implementing the add note functionality and the sub 42
step of this was to create a constant that keeps track of the title and the content so that we can save 43
what is typed into these two inputs. 44
So I'm going to open up my components folder and go to this CreateArea component. 45
Now here you'll notice that there is a very simple form with an input, a text area which acts pretty 46
much like an input, 47
and finally a button that just reads add. 48
So we've only got three components and we want to be able to save what's typed into this input under 49
something called title 50
and this one under something called content. 51
Let's go ahead and create our stateful constants and I'm going to create a object in this case that 52
contains both the title and the content. 53
You could of course create separate constants, one for the title and one for the content, 54
but it means you'll have to write more lines of code and do a little bit more work. 55
I'm going to create a constant called note and I'll create a function called setNote which is going to 56
update it. 57
And I'm of course going to need to use state. The initial state is just going to be an object with a 58
title key that's set to an empty string and a content key that's also set to an empty string. 59
Now I can use this note inside my input and my text area. 60
So I'm going to have two values and this one is going to be equal to note.title and this one will 61
be note.content. Now that we've got our inputs controlled, 62
the next step is to update them when they get changed. 63
So inside the input and the textarea I'm going to add a onChange. And inside both of these onChange 64
I'm going to call a function which I'll call handleChange. And then we can pass it in as the onChange 65
for both of these like 66
so. Now handleChange is going to receive an event when it gets triggered 67
and in this case we're going to destructure the event so that we get hold of the event.target. 68
name and .value. 69
So we're going to create a new destructured object using the const keyword and this destructured object 70
is going to tap into the event.target.name and event dot tevent.target.value like so. 71
So now we can use this name and value as separate constants and I'm going to add to my note by calling 72
setNote. Now setNote is going to be able to receive the previous note and I'm going to use that to 73
add to the existing note. 74
So in my setote I'm going to return a new object with the previous note 75
and in addition I'm going to add the new name and value. And remember that this syntax simply turns this 76
name key from just the string name for the key to the actual value of this name constant. 77
And this is of course the spread operator which is going to spread all of the key value pairs that is 78
currently in existence in our note. 79
And it's going to add it to this final object. This way when we start typing 80
then you'll see it being saved inside our state. 81
So if I go ahead and click on my create area, extend my state object, 82
this is a title and this is the content. 83
So if you're not seeing this then there might be something that you're missing in your code. 84
So this is the first step. 85
We've created a constant that keeps track of the title and the content. The next step is to somehow pass 86
this newly created note back to the app. So we know that we've got this note saved in this constant and 87
we know that we have a button called add which is supposed to trigger this adding of the note functionality. 88
So why don't we go ahead and add a onClick to this button and try to get this note that's been created 89
here passed back to the App.jsx? 90
So when this button gets clicked, we're going to pass it a function that should be triggered. 91
So in this case I'm just going to call that function submitNote and this submitNote is going to be 92
triggered here. 93
Now remember what we said about forms and buttons inside forms. 94
Whenever you click on a button inside a form, the default behavior is to refresh the page. And you can 95
see that if I type something in here and I click add, you can see the entire screen flashes and refreshes. 96
So the first thing we need to do is to prevent this. So we can pass the event to this submitNote and 97
the event is triggered by the onClick and we can call event.preventDefault. 98
This way you'll notice if I go back over here and I type something in here and I click Add, notice how 99
the screen is not flashing anymore. So I'm preventing this entire reloading of the page by using the 100
event.preventDefault which we saw in previous lessons. 101
The next thing to do is to somehow trigger a function that can pass this note back over to the App, 102
jsx. And to do that 103
we of course have to pass in a function as a prop. 104
So let's go ahead and create a function called addNote and this addNote is going to receive a note 105
object and it's going to do something with that note object. 106
So that addNote is going to be added as a value to one of the props for the create area and you can 107
call it anything you want but I'm going to call it onAdd and I'm going to set it equal addNote . 108
So now if we take a look at our components when we head over to create area it gets a prop under the 109
property name of onAdd and that is going to be equal to the addNote that comes from the App. 110
js. 111
Now we are going to trigger this addNote by getting hold of the props that gets passed over and especially 112
the props.onAdd. And calling this onAdd from the props is going to be equivalent to calling the 113
addNote from the App.jsx. And in order for us to be able to add the note we have to pass it back 114
as an input. 115
So in the onAdd we're going to pass over the current created note, like so. Now we're pretty much done 116
with our second step which is passing the new note back to the app. 117
And if you go into this addNote and go ahead and try to log the note just to check that it works, then 118
you can see that if I go ahead and just type some gibberish in here and click add and I look in 119
my console, then you can see that the only place where I'm logging it is inside my app component inside 120
the addNote function and I'm now able to receive this note and be able to log it right here. 121
So all is good in the world. 122
The next sub step is to add this new note to an array. 123
This is going to happen in our App.jsx and that array is going to need state because it's going 124
to be changed. 125
Let's create a constant and I'm going to call it notes to represent the plural nature of our array of 126
notes. And then I'm going to create a function called setNotes which is going to help me update this 127
notes array. 128
Then we of course have to use state and import state and the initial value for my notes is just going 129
to be an empty array. Instead of having this sort of sample note up here, 130
I'm just going to start it out with no notes and only when the user actually adds one does it get populated. 131
Now that we have this notes array and we're receiving the new notes via this function, then we can think 132
about how we can add to this notes array. So we can probably use these setNotes function and inside 133
this function we're going to get a hold of the previous notes or whatever is the previous value of this 134
notes array which at the moment it's empty but soon it's going to be populated with notes objects. And 135
to add to this notes array we're going to use the spread operator again so that we get hold of all of 136
the previous notes and then add the new note at the end. If you find it easier it might be worth changing 137
this property to new note 138
and remember you can call it anything you want here as long as you know that this value is being passed 139
over from here. 140
So now that we've created this array we're going to have to return it to get rid of that little squiggly 141
line 142
so that setNotes actually gets a array being returned and that is going to be set as the new notes 143
array. 144
So now all we have to do is the last step which is to take the array and render separate note components 145
for each of the items in the array. 146
Notice how we've got the squiggly line under notes and it's because we're not using it anywhere. 147
So let's do that right here. 148
So at the moment I've got a sample note being created but instead of creating the sample note, I want 149
to use my notes array and map through it to render a different note component for each item inside the 150
array. 151
My map is going to take a function and I'm just going to create an arrow function in this case. 152
And for each of the note items inside this notes array remember that the map function is going to loop 153
through this notes array and get hold of each of the note items inside and execute this function. 154
Then I'm going to return a new note component and this note component is going to need some properties 155
passed over. 156
So one of these is going to be the title which is going to be set as noteItem.title. 157
The next is the content which is going to be the noteItem.content. 158
And now in order for this code to be recognized as Javascript I'm going to go ahead and select all of 159
it and add the curly braces around it so that my errors go away. 160
So now I can replace this static note with the notes that are created from my create note component. 161
And if I go ahead and try it out 162
so I've got a title, 163
'This is a new note and here is some content'. 164
I click Add and it gets added down in here. My array gets a new object with some title and some content 165
like so. That's step one completed, implementing the add note functionality. 166
Step two is to implement the delete note functionality and the first step of doing this involves creating 167
a callback from the note component to trigger a delete function. Inside our note component we have a delete 168
button. 169
And what we want to do is to be able to somehow get this delete button to trigger a function in the 170
App.jsx. And to do this we're going to have to rely on our props. 171
We're going to have to tap into the onClick attribute here. 172
And when the button gets clicked we're going to handle the click and I'm going to create a function 173
up here which is going to be called handleClick. 174
Now you can of course have this as an inline anonymous arrow function if you want, but I'm just gonna 175
keep it separate 176
so it's a little bit easier to see what's going on. Now inside this handleClick is where we're going 177
to trigger a function that gets passed over from the props that will delete this note from the array. 178
So back in our app component, we're going to create a another function below the addNote which is going 179
to be deleteNote. And we're going to need the id of the note that needs to be deleted. 180
And then this function as it is is going to be passed over to each of these notes that gets rendered 181
as a property. 182
So I'm going to call it onDelete and I'm going to add it inside here 183
deleteNote as the function that's going to be passed over. 184
So now if we go ahead and create a note and add it when we click on the note component in our React dev tools, 185
you can see that it's got a prop called onDelete that we can tap into which is going to trigger the delete 186
Note function. Inside our Note.jsx, inside the handleClick function 187
we're going to tap into props.onDelete and that's going to trigger this function right here. 188
So let's go ahead and log that this delete was triggered. And now if I go ahead and create a new note, 189
click Add and click delete, then you can see that 'Delete was triggered' gets printed in the console. 190
So we're now able to trigger our deleteNote function in our app component but instead of console logging 191
we're probably going to want to somehow remove the note from our notes array. So we can do that using 192
setNotes. And inside setNotes we can get hold of the previous notes just as we did up here. 193
So let's go ahead and create a new arrow function which uses the previous notes. 194
Now once we have access to all of the previous notes array, well then we can loop through it using the 195
filter function. 196
And remember that the filter function takes a function that accepts up to three arguments. 197
We can go ahead and add a arrow function inside. 198
So this is our function that's being passed to our filter function 199
and it can take up to three arguments. 200
The first one is the value that we're currently looping through in the array. 201
So that's going to be the noteItem. 202
And the second one is the index of this item. 203
So that's going to be really useful very shortly when we're going to be checking to see which ones we 204
want to filter out. Inside our filter function 205
we're going to return all of the notes where the index does not equal the id of the note that needs 206
to be deleted. 207
So this way we should end up with an array that contains everything in the previous notes other than 208
the ones where the index matches the id of the note to be deleted. And we're going to need to return 209
it in order to set it as the new notes array. The last thing we need to do is somehow pass over the index 210
of the note that is being deleted through this deleteNote function. 211
Now at the moment when we create our note, we actually don't pass over 212
firstly the required key attribute but also some sort of id attribute that we can then pass back when 213
we want to delete that note. 214
This is the last step in the challenge. Somehow passing id over to the note component and pass it back 215
to the app when deleting. 216
How do we create this id? 217
We can of course create the id using a uuid or some sort of timestamp that's unique. 218
But the simplest way in this case is to know that map works very similarly to filter. In that in the 219
callback function, 220
you can have the value but you can also get the index of the current item that's being looped through. 221
Let's go ahead and add a set of parentheses around our note item because we're going to add a second 222
parameter which is the index. And we're going to use that index both as the key and also as the id. 223
When each of these note components are rendered 224
we're going to be passing over the index of the noteItem from the notes array as the id which we 225
can then pick up inside our note component so that when we call props.onDelete we pass over that 226
prop id. So we can happen to props.id and send it back when we trigger the onDelete. 227
So now if we hit save and we check it out, 228
so let's create a new title 'A new note' and click add, and then if we click delete it will disappear from 229
the array. Now the last a little bug that you might want to address is when you click on the add button 230
the title and the content should really clear itself. 231
So how can we do this? Well inside our createArea 232
once we've submitted the note, we can also clear out this note object. We can call setNote and we can 233
pass it the same object that we had to begin with. 234
This way when we call submitNote, the note gets added over to our App.jsx and we set the note state 235
to both an empty title and an empty content. And because our input has the value of note.title, our text 236
Area has a value of note.content, it should reflect the state of the notes. 237
Let's try it out. 238
If we type something in title, type something in the notes, click add and they both disappear and go back 239
to the original placeholder text. 240
So this is the solution to the full challenge and it's a really long one and it's a really hard one 241
but there isn't anything that you haven't learnt in previous lessons. 242
So if you got stuck in any of these places then be sure to head back to the relevant section where we 243
covered it so that you can get a little bit more familiar with each of these steps so that you could 244
complete this challenge comfortably by yourself. 245
Now all we have left is some tidying up and in the next lesson I want to show you how you can add some 246
dependencies using React to get hold of some components that we can use in our React apps. 247
So for all of that and more, I'll see you there.