useState
is a Hook that needs to be called inside a function component to add some local state to it. React will preserve this state between component re-renders.
There are many use cases for the useState
hook, but in this article, I will focus on the following five:
useState
use cases
- State management
- Conditional rendering
- Toggle flags (true/false)
- Counter
- Get API data and store it in state
State management
Let's start with a warning: don't write code in this way, because it will create an infinite loop:
import { useState } from "react";
const UseCaseStateManagement = props => {
const [state, setState] = useState('initial value');
setState('new value');
console.log(state);
return (
<>
<h2>useState use case</h2>
<h3>State management</h3>
<hr />
<p>{state}</p>
</>
);
};
export default UseCaseStateManagement;
The loop is created because the initial render calls the state update function setState
, which in time triggers a re-render and a new function evaluation.
If we want to change a state due to an action performed by the user, we can do this:
import { useState } from "react";
const UseCaseStateManagement = props => {
const [state, setState] = useState('initial value');
console.log('๐ This is a re-render');
const clickHandler = () => {
setState('new value');
};
return (
<>
<h2>useState use case</h2>
<h3>State management</h3>
<hr />
<button onClick={clickHandler}>Set state</button>
<p>{state}</p>
</>
);
};
export default UseCaseStateManagement;
That state will be preserved across component re-renders and we will be able to make use of it in the newest re-render.
Conditional rendering
We can use a state to conditionally render a component or part of it.
import { useState } from "react";
const UseCaseConditionalRender = props => {
const [condition, setCondition] = useState(false);
const clickHandler = () => {
setCondition(true);
};
return (
<>
<hr />
<h2>useState use case</h2>
<h3>Conditional Rendering</h3>
<button onClick={clickHandler}>Set condition</button>
{condition && <p>Hello!</p>}
</>
);
};
export default UseCaseConditionalRender;
Toggle flags
useState
can be used to toggle between two values, usually true
and false
, in order to toggle a flag, such as the display mode:
import { useState } from 'react';
import classes from './UseCaseToggle.module.css';
const UseCaseToggle = props => {
const [mode, setMode] = useState(false);
// Use setState function form because the new state depends on the previous one
const clickHandler = () => {
setMode(prevState => !prevState);
};
const toggledClass = mode ? classes.light : classes.dark;
return (
<div className={toggledClass}>
<hr />
<h2>useState use case</h2>
<h3>Toggle flags</h3>
<button onClick={clickHandler}>Toggle display mode</button>
</div>
);
};
export default UseCaseToggle;
The result will be an alternation between dark and light mode on the component.
Counter
useState
can be used to keep track of a variable through multiple re-renders, such as in a counter application:
import { useState } from "react";
const UseCaseCounter = props => {
const [counter, setCounter] = useState(0);
// Use setState function form because the new state depends on the previous one
const clickHandlerDecrease = () => {
// Converting the prevState to number to avoid errors
setCounter(prevState => +prevState - 1);
};
const clickHandlerIncrease = () => {
setCounter(prevState => +prevState + 1);
};
return (
<>
<hr />
<h2>useState use case</h2>
<h3>Counter</h3>
<button onClick={clickHandlerDecrease}>--</button>
<span> {counter} </span>
<button onClick={clickHandlerIncrease}>++</button>
</>
);
};
export default UseCaseCounter;
Get API data and store it in state
A more complex use of this hook is presented when we need to interact with an API. In this case, we can use a state to store the response of a fetch()
to the API, and the state of a spinner that will indicate if the data is being fetched.
import { useState } from "react";
const UseCaseApi = props => {
const [starship, setStarship] = useState('');
const [isLoading, setIsLoading] = useState(false);
const clickHandler = async () => {
setIsLoading(true);
const response = await fetch('https://swapi.dev/api/starships/10');
const data = await response.json();
setStarship(JSON.stringify(data, null, "\t"));
setIsLoading(false);
};
let message = '';
if (isLoading) {
message = <p>Getting data... ๐</p>;
}
return (
<>
<hr />
<h2>useState use case</h2>
<h3>Get API data and store it in state</h3>
<button onClick={clickHandler}>Get Millennium Falcon data</button>
<p>{message}</p>
<pre>{starship}</pre>
</>
);
};
export default UseCaseApi;
You can watch all these examples live here.
You can also take a look at the code in this repository.
๐๏ธ NEWSLETTER - If you want to hear about my latest articles and interesting software development content, subscribe to my newsletter.
๐ฆ TWITTER - Follow me on Twitter.