Day 30: React
Lesson 2: State
When state (data) changes in our app, React will work out what needs to be updated in the DOM for us. It knows what has changed by monitoring data that we say are state.
State is a fancy name for data that we care about
. Broadly speaking, if some piece of start changes then react will reinvoke the function that creates the component. In this case the App()
function.
Let's add some state and change it.
React allows us to add functionality to components with things called hooks. The hook we care about here is the useState
hook.
Change your App.js
to look like this:
1import React, { useState } from "react"; 2import "./style.css"; 3 4export default function App() { 5 const [count, setCount] = useState(0); 6 7 return ( 8 <div> 9 <h1>Hello All The Code!</h1> 10 <p>Start editing to see some magic happen :)</p> 11 </div> 12 ); 13}
Note changed import at the top and the new line at the start of the function.
useState()
returns an array with two elements. The first is the value of the data it is managing, the second is a function to use to update that data. Notice how we are using destructuring to access those two returned values, this is a very common patter in React.
If you pass an argument into useState()
this will set the initial value.
So in this case we have set a const
called count
to 0. Even though we will be changing count
we create it as a const
because we won't update it directly. We will use setCount
to do that.
Now add a this in place of the code currently in between the <div>
tags:
1<div>Count: { count }</div> 2<button onClick={onHandleClick}>Add 1</button>
We will create the onHandleClick
function in a minute.
The first line here uses { count }
to display the value of the count constant. While this all looks like HTML it's not really, it's JSX, which is just a weird flavour of JavaScript. This means we can add JavaScript in anywhere we want just by putting in some curly braces 😀
The second line is a button with an onClick
handler. Here is another clue that this is JSX and not HTML. In HTML this would have been onclick
but because this is JSX we use onClick
instead - and yes, many React developers have lost hours wondering why events aren't firing thanks to this, for either forgetting the capital letter in React or adding the capital in HTML (usually the latter since it fails silently without an error 🤦♂️)
Now add this function above the return
line and after useState
line:
1const onHandleClick = () => { 2 setCount(count + 1); 3};
This is the event handler function that calls the setCount
function with a new value. We pass in count + 1
. What we can't do is change count
directly and then pass it in.
So this is no good:
1const onHandleClick = () => { 2 count = count + 1; 3 setCount(count); 4};
This would be ok though:
1const onHandleClick = () => { 2 const newCount = count + 1; 3 setCount(newCount); 4};
So long as the only thing that sets count
is setCount
then you're good.
When you save that you can click the button and watch the count change.
Even with this small example I think you can see why React is so popular. We didn't need to use document.getElementById
or any of that rubbish.
You change the data and the UI updates, that's declarative programming for you.
Before we move on to the next lesson I want you to delete the <div>
and </div
in the return block of App()
.
You will immediately see this error:
1JSX expressions must have one parent element.
This means that you can't have two JSX components next to each other at the top of a return.
If you don't want to wrap them in a <div>
like we have here, which will appear in the DOM, you can use a fragment instead, which is just an empty set of tags.
1<> 2 <div>Count: {count}</div> 3 <button onClick={onHandleClick}>Add 1</button> 4</>
This is because under the hood React is calling functions and a function can't return more than one thing, having two JSX tags next to each other at the top level, is like trying to return two things from a function. You need to wrap them in another, single JSX tag at the top level to solve this.