Last updated: Apr 7, 2024
Reading timeยท3 min
To toggle a boolean state in React:
useState
hook to track the state of the boolean.setState
function the hook returns.import {useState} from 'react'; export default function App() { // ๐๏ธ Initialize boolean to false const [isLoading, setIsLoading] = useState(false); const toggleIsLoading = () => { // ๐๏ธ Passed function to setState setIsLoading(current => !current); }; return ( <div> <button onClick={toggleIsLoading}>Toggle loading state</button> {isLoading && <h2>bobbyhadz.com...</h2>} </div> ); }
We passed a function to setIsLoading
because the function is guaranteed to be
called with the current (most up-to-date) value for the isLoading
boolean.
const toggleIsLoading = () => { // ๐๏ธ passed function to setState setIsLoading(current => !current); };
In the example, we simply toggle the boolean and return the result to update the state.
We used the logical NOT (!) operator to flip the boolean value.
Here are some examples of using the logical NOT operator.
console.log(!true); // ๐๏ธ false console.log(!false); // ๐๏ธ true
If you try to access the isLoading
state variable immediately after using the
setIsLoading
function to update it, there is no guarantee that you'll get the
current (most up-to-date) value.
If you need to listen to state changes, add the state variables to the dependencies array of the useEffect hook.
import {useEffect, useState} from 'react'; export default function App() { const [isLoading, setIsLoading] = useState(false); const toggleIsLoading = () => { // ๐๏ธ Passed function to setState setIsLoading(current => !current); }; useEffect(() => { // ๐๏ธ If you need to listen for changes of isLoading boolean console.log('isLoading is: ', isLoading); }, [isLoading]); return ( <div> <button onClick={toggleIsLoading}>Toggle loading state</button> {isLoading && <h2>bobbyhadz.com...</h2>} </div> ); }
We added the isLoading
state variable to the hook's dependencies array, so any
time isLoading
changes, the logic in our useEffect
hook will rerun.
Note that the hook is also invoked when the component mounts.
Here is an example of how to toggle boolean state and make an HTTP request only
when the state is equal to true
.
import {useEffect, useState} from 'react'; export default function App() { const [isActive, setIsActive] = useState(false); const [data, setData] = useState({data: []}); const toggleIsActive = () => { setIsActive(isActive => !isActive); }; useEffect(() => { console.log('isActive is: ', isActive); if (isActive) { fetchData(); } else { setData({data: []}); } }, [isActive]); const fetchData = async () => { const response = await fetch('https://reqres.in/api/users', { method: 'GET', headers: {Accept: 'application/json'}, }); const result = await response.json(); console.log('result is: ', JSON.stringify(result, null, 4)); setData(result); }; return ( <div> <button onClick={toggleIsActive}> Toggle active state </button> {isActive && <h2>bobbyhadz.com...</h2>} {data.data.map(person => { return ( <div key={person.id}> <h2>{person.email}</h2> <h2>{person.first_name}</h2> <h2>{person.last_name}</h2> <br /> </div> ); })} </div> ); }
We used the useEffect
hook to check if the boolean state is equal to true
.
If it is, we fetch data from a remote API, otherwise, we set the data
state to
its initial value.
useEffect(() => { console.log('isActive is: ', isActive); if (isActive) { fetchData(); } else { setData({data: []}); } }, [isActive]);
When the state is toggled, the data is shown or hidden depending on if its value
is true
or false
.
If you don't want to run the logic in your useEffect
hook on the initial
render, but only when the specific state variable changes, use a ref
to return
early on the initial render.
import {useEffect, useState, useRef} from 'react'; export default function App() { const [isLoading, setIsLoading] = useState(false); const toggleIsLoading = () => { setIsLoading(current => !current); }; const isFirstRender = useRef(true); useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; // ๐๏ธ Return early if first render } console.log('isLoading is: ', isLoading); }, [isLoading]); return ( <div> <button onClick={toggleIsLoading}>Toggle loading state</button> {isLoading && <h2>bobbyhadz.com...</h2>} </div> ); }
We used a ref to exit early when the
useEffect
hook is run on mount.
useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; // ๐๏ธ Return early if first render } console.log('isLoading is: ', isLoading); }, [isLoading]);
If the ref's value is set to true
, we return early from useEffect
and set
the ref's value to false
.
The next time the useEffect
hook runs, the ref's value is set to false
and
the remainder of the hook runs.
Use this approach if you want to listen for state changes but need to skip the first render.
I've also written an article on how to render a boolean in JSX.