useState Hook
The useState Hook is the most similar to traditional state in React class-based components, and we'll look at examples of how it works to keep track of state in functional components.
Here is the useState
Hook, a hook we'll become intimately familiar with over this course.
It's the one you will reach for the most in our new, state-powered functional components, and it's the one most similar to the this.state
you already know and love in React.
We'll learn how useState
stacks up to traditional class state in this lesson and how to replace it effectively with hooks.
Sample useState code#
Below are two interactive examples of how the useState
Hook can be used. I have two examples because this hook can be used with slight modifications depending on if you need to access previous state to update the current state or not.
Show message (An example where previous state doesn't matter)#
In the top example (which doesn't depend on previous state), when you click the Hide Message button, the state of showMessage
is updated from true
to false
, and the message displayed in the JSX goes from When 'showMessage' is true, you see me
to When it's false, you don't
.
Let's break down each part of this first example, and compare it to its class-based equivalent. We'll look at declaring state, then reading state, and finally updating state with useState
.
Declaring showMessage state with useState#
useState
returns a pair: the current state value and a function that lets you update it.
It's a best practice to name the function as
setXYZ
to match whatever you name your state value. So if your state variable wasisOnline
, your matching function to update that variable would besetIsOnline
.
You can call this function from an event handler or somewhere else. This hook is like this.state.showMessage
and this.setState
in a class, except you get them as an array destructured pair and useState
doesn’t merge the old and new state together like this.setState
does.
In a class-based component, initializing state looks like this:
Class component
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showMessage: true,
};
}
// other JS code goes here
}
The equivalent code in a functional React component using useState
looks like this:
Functional component
import { useState } from "react";
import "./styles.css";
const App = () => {
const [showMessage, setShowMessage] = useState(true);
Since there is no this
in functional components, nothing can be assigned or read from this.state
, so instead, the useState
Hook is called directly inside the component.
Calling useState
declares a “state variable”. Our variable is called showMessage
, but it could be named whatever you want, like waffle
or location
. This is a way to “preserve” some values between the function calls — useState
is a new way to use the exact same capabilities that this.state
provides in a class. Normally, variables “disappear” when the function exits, but state
variables are preserved by React.
The only argument the useState()
Hook needs is the initial state (true
, in this case). And unlike with classes, the state doesn’t have to be an object. It can be a number, a string, even a boolean if that’s all we need.
In our example, we need a boolean to determine if the user should see one message versus another in the DOM, so the initial state is set to true
for the showMessage
variable. (If we wanted to store two different values in state, we would call useState()
twice and declare two different pairs of state — you'll see plenty of this sort of thing when we refactor the sample app.)
A best practice for
useState
is to declare all the variables at the top of the component right after defining it (like how we declare state values at the top of class-based components today).
Now that the state's been set in the component, let's compare how its value is read.
Reading showMessage state with useState#
Here's how a class component would update the state of showMessage
.
Class component
export default class App extends React.Component {
// state is set up here
render() {
return (
// render some other JSX here
{this.state.showMessage ? (
<h3>When `showMessage` is true, you see me.</h3>
) : (
<h3>When it's false, you don't</h3>
)}
);
}
}
Instead of calling {this.state.showMessage}
to read the value of showMessage
in a class-based component, we can simply call {showMessage}
in a functional component.
Functional component
<div className="App">
<h1>useState Examples</h1>
<h2>
When showMessage's state is updated, previous state doesn't matter much.
</h2>
<h3>
Current showMessage State:
{showMessage ? <span>true</span> : <span>false</span>}
</h3>
<h2>{showMessage}</h2>
{showMessage ? (
<h3>When `showMessage` is true, you see me.</h3>
) : (
<h3>When it's false, you don't</h3>
)}
While displaying the value in this example of a class-based component above doesn't seem like that much more code, when you have many state variables being displayed in a single component, it can be much harder to decipher what all is going on in the component.
This page is a preview of The newline Guide to Modernizing an Enterprise React App