Last updated: Apr 6, 2024
Reading timeยท3 min

Use the useEffect hook to only call a function once in React. When the
useEffect hook is passed an empty dependencies array, it is only run when the
component mounts.
This is the preferred approach when you have to fetch data when the component mounts.
import {useEffect, useState} from 'react'; const App = () => { const [num, setNum] = useState(0); useEffect(() => { // ๐๏ธ Only runs once console.log('useEffect ran'); function incrementNum() { setNum(prev => prev + 1); } incrementNum(); }, []); // ๐๏ธ Empty dependencies array return ( <div> <h2>Number is {num}</h2> </div> ); }; export default App;

The incrementNum function is only called once - when the component mounts.
The second parameter we passed to the useEffect hook is an array of dependencies.
We specified an empty array of dependencies, so the function we passed to the
useEffect hook will only be called once.
Notice that we defined the incrementNum function inside of the function we
passed to the useEffect hook.
Alternatively, we could have defined the function outside of the component or memoized it.
Here is an example of how you would call a function to fetch data only once - when the component mounts.
import {useEffect, useState} from 'react'; const App = () => { const [data, setData] = useState({data: []}); const [err, setErr] = useState(''); useEffect(() => { // ๐๏ธ This only runs once console.log('useEffect ran'); // ๐๏ธ fetch data from remote API async function getUsers() { try { const response = await fetch('https://reqres.in/api/users', { method: 'GET', headers: { Accept: 'application/json', }, }); if (!response.ok) { throw new Error(`Error! status: ${response.status}`); } const result = await response.json(); console.log('result is: ', JSON.stringify(result, null, 4)); setData(result); } catch (err) { setErr(err.message); } } getUsers(); }, []); // ๐๏ธ Empty dependencies array console.log(data); return ( <div> {err && <h2>{err}</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> ); }; export default App;

We defined a getUsers function inside of the useEffect hook. The function is
called only once - when the component mounts and makes a single request to a
remote API to fetch some data.
useEffect hook is run only once because we passed it an empty dependencies array as the second parameter.If you need to fetch data on button click, check out the following article.
An alternative to defining the function you want to only call once inside of the
useEffect hook is to define the function outside of the component.
useCallback hook to memoize the functionAlternatively, you can use the useCallback hook to memoize the function and
pass it to the dependencies array of useEffect.
import {useCallback, useEffect, useState} from 'react'; const App = () => { const [num, setNum] = useState(0); // ๐๏ธ Memoize function (doesn't get re-created every render) const incrementNum = useCallback(() => { setNum(prev => prev + 1); }, []); useEffect(() => { // ๐๏ธ This only runs once incrementNum(); // ๐๏ธ Include it in the dependencies array }, [incrementNum]); return ( <div> <h2>Number is {num}</h2> </div> ); }; export default App;

The useCallback hook takes an inline callback function and a dependencies
array and returns a memoized version of the callback that only changes if one of
the dependencies has changed.
Now that the incrementNum function is stable and doesn't change between
renders, we can safely add it to the dependencies of the useEffect hook and it
still runs only once.