An Introduction to the useState() Hook
August 12, 2019
React introduced the Hooks API as of version 16.8 which gave us the ability to utilize (or “hook into”) certain features of React within a functional component that previously required the use of a class component. React provides some built-in hooks as well as the ability to create our own custom hooks. These custom hooks allow us to reuse some stateful logic between components. The focus of this post will be on the useState
hook which allows us to make our functional components stateful.
State Management in React
Traditionally in React, only class components had the ability to manage their own state. Function components were even often referred to as “stateless functional components”. We were often encouraged to use functional components when state and lifecycle methods weren’t necessary. This paradigm led to the annoyance of having to covert functional components to class components if it was ever determined that we needed to add state (or access lifecycle methods) in our component.
Class Components
The way we manage state in class components is by initializing state values in the state
property and updating these values with the setState
method.
class Theme extends Component {
state = {
theme: 'dark',
};
toDarkTheme = () => this.setState({ theme: dark });
toLightTheme = () => this.setState({ theme: light });
render() {
return (
<div className={this.state.theme}>
{theme === 'light' ? (
<button onClick={this.toDarkTheme}>🌛</button>
) : (
<button onClick={this.toLightTheme}>🌝</button>
)}
</div>
);
}
}
Function Components and the useState Hook
React provides us with the useState
hook which gives us the ability to manage state within a functional component. useState
is simply a function that takes one argument, our initial state value, and returns an array of two items. The first item in the returned array is the current value of our state and the second item is a function to update that state.
import React, { useState } from 'react';
function Theme() {
const [theme, setTheme] = useState('dark');
const toDarkTheme = () => setTheme('dark');
const toLightTheme = () => setTheme('light');
return (
<div className={theme}>
{theme === 'light' ? (
<button onClick={toDarkTheme}>🌛</button>
) : (
<button onClick={toLightTheme}>🌝</button>
)}
</div>
);
}
The first line within our Theme
component example shows how we initialize a state value by calling useState
and passing it the initial state value. We are also utilizing array destructuring to gain access to the two values returned by useState
.
In order to update the state value, we call the setTheme()
updater function that was returned to us from useState
. This updater function takes an argument that represents our new state value. It should be noted that theme
and setTheme
could be called anything we would like, but naming these values thing
and setThing
is a widely used naming convention.
Functional Updates
Just as calls to setState
are asynchronous, so too are updates to state using the useState
hook. Whenever we are updating state based on the previous state, in order to ensure the value returned by useState
is up to date, you should pass a function to your updater function. As shown in the highlighted line in the example below, we pass setTheme
a function which passes in the current value of theme
and returns a new value based on the previous state.
import React, { useState } from 'react';
function Theme() {
const [theme, setTheme] = useState('dark');
const toggleTheme = () => setTheme((theme) => !theme);
return (
<div className={theme}>
{theme === 'light' ? (
<button onClick={toggleTheme}>🌛</button>
) : (
<button onClick={toggleTheme}>🌝</button>
)}
</div>
);
}