How to only call a function Once in React

avatar

Borislav Hadzhiev

Sat Apr 16 20223 min read

banner

Photo by Eunice Stahl

Only call a function Once in React #

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 ran when the component mounts. This is the preferred approach when you have to fetch data when the component mounts.

App.js
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.

The first parameter is a function that gets invoked when the component mounts and any time the dependencies in the array change.

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.

We did this, so we don't have to add the function to the hook's dependencies array.

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.

App.js
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.

The useEffect hook is ran only once because we passed it an empty dependencies array as the second parameter.

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.

If the function is defined outside of the component, it won't get re-created every time the component renders and will be stable and therefore doesn't have to be added to the hook's dependencies array.

Alternatively, you can use the useCallback hook to memoize the function and pass it to the dependencies array of useEffect.

App.js
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 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.

Use the search field on my Home Page to filter through my more than 1,000 articles.