Hey guys. In this lesson, I want to tackle this idea of state and introduce you to React
Hooks as a way of being able to make our website interactive and actually have changeable state.
Go ahead and fork
the starting project for this lesson. And once you're done,
have a look at what we've got here. Now,
unlike our previous React apps, I've actually got all of my React code currently living inside my index.js
and there's a reason for this that you're going to discover very soon.
But inside our index.js,
the code is very simple,
All that we're doing is rendering a single div that has an <h1> and a button contained inside it.
The idea is simple. How can we get this button to trigger an update in this number so that every time
the user presses on this plus button, this number actually goes up in value?
So let's think about how we might approach this.
Well firstly, this h1 has a hardcoded value in it,
so that's not going to work.
So let's go ahead and create a new variable called count and let's set it equal to 0 and then we'll
replace this hardcoded value with this variable count.
Nothing has changed so far in the user interface.
Now the next thing we need to do is to be able to trigger some piece of code to happen whenever this button
is clicked.
So we know from our HTML that all of our button elements have an attribute called onClick, and we
can set that to equal some sort of function to be triggered when this button receives a click action.
Now we know that when we're creating React components that all of these HTML elements, and their attributes
gets converted into camel case,
so something like this. So we can in fact set this onClick attribute to a function in our code.
So let me create a function called, increase, and all that I'm going to put inside is just a simple log
statement saying, 'I got clicked.' And now in our onClick, I'm going to add a set of curly braces and assign
it that function.
Now what should happen is when I click this plus button, then it should call this function increase and
it should log this message and indeed it does.
If you look inside the console I get a new message being logged every time I press this button.
So our code is working. But how can we increase the count that's being shown here?
Well, one way you might think of doing this is to simply just write count++
and this should increase the value of count every time the function increase is called.
And indeed it does.
Let's go ahead and log the value of count inside the increase function
and then I'm going to click on the plus button. And you can see that in the console which is logging
the value of count, it is indeed increasing by 1
each time I press the button, but our user interface is not changing at all.
Nothing is happening,
it looks dead to me.
So what's going on here?
Well, remember that even though we're writing HTML elements, they're not actually real elements, right?
We're relying on the ReactDOM to actually render each of these elements onto the screen.
So if we wanted to update what's on screen we actually have to re-render all of this.
So if we wanted this to update, one way of doing this instead of console logging, would be to call
ReactDOM.render all over again inside our function.
Now if I hit save and I click the plus button, you can see that it does indeed work.
And every time I press this button effectively what it's doing is re-rendering everything that's on
screen which is our div, and our h1, and our button.
And this is kind of inefficient,
right?
And besides the code also looks terrible.
We have all of this repetition
that's not really doing anything for us.
So how do people actually solve this problem using React?
Well, this is where Hooks comes in. And there's a Hook called useState that is perfect for this situation.
But one of the rules for using hooks is that you must use a hook inside a functional component,
so we have to create a function that renders a component and then inside that function, we can use hooks.
So let's go ahead and import our App.jsx,
and move all of our code into our App.js. And then back in our index.js
all we need is our ReactDOM.render,
and then we're just rendering a simple App component.
So now we can focus on our App component.
And I'm going to just start off by wrapping everything inside a function which is called App so that
this gets rendered and, instead of using ReactDOM.render and all of this document.getElement et cetera,
all I'm going do is just use the return statement, so that this becomes the output of our App component
and it gets created on screen, which you can see right here.
Now I'm going to delete all of this repeated ReactDOM code, and you should be left with something that
looks like this.
Now inside our App component, instead of using this count, I'm going to create a new const that I'm
going to call state and I'm going to set the state to
React.useState which is a function.
Now this useState function comes from the react module, so I can either call it like this, or as you've
seen from the import and export lesson,
we can also just add a comma and then a set of curly braces and import that useState function as a
non-default export.
So now instead of saying React.useState I can simply just write useState whenever I need it.
Now what is this
useState
exactly,
anyways? So I'm going to go ahead and comment out my count and also I'm going to delete the count that
currently lives inside my h1 so that I get rid of my errors. And instead, I'm just going to log what this
state is actually equal to.
Notice how state holds the return value of this function useState.
And if I log it you can see it's comprised of an array with two items. The first item seems to be undefined
and the second item is some sort of function.
If I go ahead and add a value in here let's say 0
and again my console.log() gets triggered,
you can see the first value of my array gets replaced with whatever it is that I put in here.
What's inside these parentheses is basically our starting state and if we wanted to get hold of this
value through this state, we can simply say state[0].
So that gets hold of the initial value that we put into this function.
And of course, now we can then use this state inside our React component.
So I'm going to replace that hardcoded 0 once more, but this time I'm going to tap into this new array
called state, and get hold of the first value. And you can see it's now being displayed on screen.
And whenever I change my state, you'll see it update automatically in our h1.
So effectively we're telling this h1 to track the value of our state,
and whenever the state updates, then it should also re-render this h1. This way
it's way more efficient than us calling ReactDOM.render and it only updates the parts that need to
be changed, such as this h1.
Now because the output of useState is an array we're forced to write code like this. If we want to get
hold of the first item out of that array, we're using this square bracket notation which is very ugly
because it has no meaning. At some point down the line, we're going to forget what state[0] is and it's
going to be hard to debug other issues when they come up.
Now in JavaScript
ES6,
there's this concept called Destructuring and what it allows you to do is to destructure a complex structure.
So the complex things in JavaScript are objects and arrays.
Let's say that I had a const which was a rgb color,
right?
And it was an array comprised of three values.
If we head over to flatuicolors.com which is a really nice color palette where you can simply
just copy these color values, let's change the color to the rgb format,
so red green blue. And let's just copy this electron blue color.
Now if I go ahead and paste this here, you can see that this color is comprised of three elements, the
amount of red, the amount of green and the amount of blue.
Let me go ahead and add this inside my array. If I wanted to access the amount of red, or green, or blue,
I would have to log something like rgb at index 0 for the amount of red, or 1 for the amount of
green et cetera.
And this is really bad code because it doesn't mean anything at all.
And if this code was separated from where the rgb array was declared and you just saw this out of the
blue, I mean what does that even mean,
right?
What can we do instead?
Well we can destructure this array so that instead of having this name rgb, we can use a set of square
brackets.
Remember that we're working with an array, and arrays are declared using square brackets,
so we also deconstruct them using a square bracket. And then we can provide some names for each of the
elements inside the array ordered by their positions.
So I could call the item at index 1 red, the next one
green and the last one blue.
And what's going to happen behind the scenes
is this variable name red is going to be mapped to this first value,
green is going to remap to the second value
and blue is going to be mapped to the third value.
So now if I simply just log the value of blue, you can see that third value gets outputed.
So given that we know that this useState function outputs an array with a value and a function,
then we can give each of these a name instead of just calling it state.
So let's open up a set of square brackets
and given that we're going to be using this state to hold the value of our counter, I'm going to give
the first item of the array a name which is called count.
So now whenever I want to access the value that's stored inside the state, all I have to do instead of
saying state at position 0, I can simply just tap into count and it does the same thing.
It gets hold of the output of this function, which is an array with two items and because we've only
got one name specified in our destructuring, it assigns this name to the first value which is the initial
value.
So how do we use this useState Hook to update its value?
Because yeah, it's great that we can change the initial value but how can we change it later on?
For example when we want to call increase. What's the equivalent of the count++?
Well, remember that we mentioned that this array that gets returned from this function has two items.
The first one is a value
and the second one is a function. Well, we can give that function a name. Let's call it setCount because
that's basically what it's going to do.
This is going to be the function that's going to be used to update this value inside our state. Inside the
increase function,
I'm going to call setCount and I'm going to pass it a new value.
So let's say maybe 12.
So now let's track what's going to happen. First, when my app loads up, I call useState and I give it
an initial value.
This value gets stored inside this variable, count and it gets rendered inside our h1.
Now when the user presses on this button and the onClick gets triggered, the increase function is activated.
And this increase function is going to call setCount which is going to update the state of my count
variable, and I'm setting it to equal 12.
Let's go ahead and take a look in our website. When we refresh,
it starts out with this initial value for the count.
And then when I press the plus button, it gets set to whatever it is that I set it to inside the increase
function.
But notice how if I keep pressing this nothing happens. It's just going to keep resetting it to 12 which
is not very useful for a counter app.
What can we do instead?
Well, let's set this count to 0 to begin with,
make it more like a counter. And then I'm going to set my count to the current value of count + 1.
So count + 1.
And now when I press this button we'll see that it just increases by 1 each time. As a challenge,
go ahead and create another button down here, and instead of increasing the value, you want it to decrease
the value.
So it should have a minus sign inside
and when you click on it, it should go the opposite way.
Pause the video now and see if you can complete this challenge.
All right. So we've got an increase function that's tied to the plus button.
But we should probably also have a decrease function that's tied to the minus button.
Now when this button gets clicked, we trigger the decrease function and inside here we are again going
to call setCount, which is the function that's going to allow us to update the value of count.
And we're going to say count - 1.
So now if we update our website and we press the plus it goes up, we press the minus
it goes down. And this is all achieved using the useState Hook. To recap, in this lesson we're introducing
this concept of state in order to have interactivity in our app.
And what we're trying to achieve is for our website to be able to update dynamically, reflecting the
updated state.
Now the state comes from this useState Hook and this function comes from the react module,
now when we first call this function, we get to define an initial value. And then we get to use this value
inside our destructed array, which we called count.
So we're putting that value of count inside our h1 and then we get to trigger the setCount which
is the function that's going to update the value of count.
And we do that when the user clicks on our plus button. And we set it to the current value of count +
1,
so it increases it by 1 each time.
Now the idea of hooks might be quite unfamiliar to you, but once you wrap your head around its mechanism,
it's incredibly powerful and really useful when you want to create any sort of interactive app.
Now don't worry if you're still trying to get to grips with this concept because it's something that
is quite foreign, and I recommend as a first step, to simply delete all of the code that you have in your
CodeSandbox right now, and then to recreate this app from scratch yourself. So delete everything that's
inside App.js and refresh yourself just simply on the syntax to begin with, because it looks pretty
weird. And in the next lesson, I've got another challenge for you to implement this useState
Hook.
So you're going to be getting plenty of practice
and we're also going to be talking about destructuring a little bit later on as well.
For now what I want you to do is just to get familiar with the syntax, be able to write this code from
scratch yourself without looking at the video and be able to understand how we actually got here in
the first place.
So pause the video now, have a play around with the sandbox and I'll see you on the next lesson for a challenge.