Getting to Know Hooks in React: useState()

R. Cory Stine
4 min readMar 25, 2022

Just as I was wrapping up the final lines of code in my very last project for Flatiron School, excited to graduate and begin my job search, a whole new section of curriculum was dropped. Eager to finish, I completed my project without looking back. However, as I dive into my career as a software engineer, I want to continue to expand my knowledge base and understanding of new concepts and tools — so I’ve decided to review that new information and reflect on it in a series of blog posts.

Enter React Hooks.

Let’s start simply: What are hooks and why are they important?

Traditionally, when working with legacy React, there were some pretty severe limitations to what you could do with functional components. They were designed for simplicity and ultimately unable to access state and lifecycle functions in the same way that class components could.

But this was all upended in 2019 when hooks were introduced. Suddenly, state and lifecycle functions, as well as a number of other React features, became fair game in functional components: allowing for improved readability and flexibility. Class components are complex and often difficult to learn. Hooks give us the chance to use simpler functional components in most, if not all circumstances, while still embracing the full power of React.

To demonstrate how hooks improve the experience of React, let’s dig into perhaps the most widely used of these functions: useState().

For comparisons sake, let’s take a look at the traditional way to initialize and change state in React. We’ll do this by creating a simple class component that renders a button that when clicked, changes text from “On” to “Off”.

import React from "react";class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "On"
};
};
handleClick = () => {
this.setState({
text: "Off"
});
};
render() {
return (
<div>
<button onClick={this.handleClick}>
{this.state.text}
</button>
</div>
);
}
}
export default Button;

You can see that even a fairly straightforward component like this is a bit noisy and overly complicated. State is initialized within a constructor and set in a separate function using this.setState(). We return our JSX within a render function. How could we do this same thing using hooks?

First, we need to import the useState function from React to gain access to utilize it. We also need to stub out our functional component, rendering an empty button.

import React, { useState } from "react";const Button = () => {
return (
<div>
<button></button>
</div>
);
};
export default Button;

Since this is a functional component, there is no this, as you would find in a class component. There’s no way to assign or call this.state. Rather, this is where we’ll implement the useState() hook.

const [text, setText] = useState("On");

What exactly is this doing? It’s a variation on state declaration. Instead of taking this action within a constructor, we create a destructured array constant whose first argument creates the name of our variable (in this case “text”) and whose second argument create a function that we can call later to change the information passed into state (“setText”). This is ultimately what is returned to us: our current state and the function used to update it.

Then, we set our const to our useState function and pass in the value we want reflected in our variable when the component first loads. If it helps, you can think of this current code as:

this.state = {
text: "On"
}

It’s basically the same as our Class component!

It’s important to note that while Class components require state to be set within an object, there is no such restriction with Functional components and useState(). You can pass in any data type: including numbers, strings, booleans, objects, etc.

When we’re ready to update our state, all we have to do is call the custom setState function we assigned above within a function. Here, that is setText(). Inside the parenthesis, our argument is the new value we would like to be reflected.

const handleClick = () => {
setText("Off");
};

To best reflect our original example, I’ve created a function called handleClick. When utilized, this will set our text variable to “Off”, making the change to state.

return (
<div>
<button onClick={handleClick}>{text}</button>
</div>
);

I pass handleClick into the onClick event listener of our button. Finally, I need to read the current state of our text variable by setting the button’s wrapped text to { text }.

Now, as required, when I click the button, the initial text of “On” will update to “Off”.

Let’s look at the whole thing put together:

import React, { useState } from "react";const Button = () => {   const [text, setText] = useState("On");   const handleClick = () => {
setText("Off");
};
return (
<div>
<button onClick={handleClick}>{text}</button>
</div>
);
};
export default Button;

This is a much more elegant solution that let’s us do the exact same thing as we did in our Class Component with more efficient code — a solution made possible by the availability of the useState hook.

If you require multiple state variables on a functional component, you can simply call useState() multiple times. For example, we could disable our button once it changes to “Off” by adding a second state variable that passes a boolean value into useState():

import React, { useState } from "react";const Button = () => {
const [text, setText] = useState("On");
const [disabled, setDisabled] = useState(false);
const handleClick = () => {
setText("Off");
setDisabled(true);
};
return (
<div>
<button
onClick={handleClick}
disabled={disabled}>
{text}</button>
</div>
);
};
export default Button;

When our button is clicked, it is set to “Off” and is grayed out and disabled to prevent additional clicks!

This is an incredibly valuable tool and one I wish I had discovered earlier, as I believe it could have dramatically cleaned up the code in my final project. I look forward to continuing to explore React Hooks so that I can apply them to my future work and hope you will join me on the journey.

--

--