Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why is React calling some of my App's functions multiple times?

I was debugging a React app and noticed that some of my functions were called multiple times in a way I could not explain.

I initially thought it was some sort of "developer feature" and tried to run a build, and all I could see if that the APIs that should not be called were called once instead of twice:

import { useCallback, useState } from "react";

function App() {
  const cities = ["montreal", "london", "shanghai"];

  const [city, setCity] = useState(cities[0]);

  const getCityParameter = useCallback(
    (newCity) => {
      console.log("[1] getCityParameter");
      console.log(`newCity: ${newCity}`);
      console.log(`city: ${city}`);
      return (newCity ?? city).toUpperCase();
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [city]
  );
  const [cityParameter, setCityParameter] = useState(getCityParameter());

  const handleChange = useCallback(
    (event) => {
      const newCity = event?.target.value;
      console.log("handleCityChange");
      console.log(`newCity: ${newCity}`);
      if (newCity !== undefined) {
        setCity(newCity);
      }
      const newCityParameter = getCityParameter(newCity);
      setCityParameter(newCityParameter);
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [city]
  );

  return (
    <>
      <select onChange={handleChange} value={city}>
        {cities.map((city) => {
          return (
            <option value={city} key={city}>
              {city}
            </option>
          );
        })}
      </select>
      <div>{cityParameter}</div>
    </>
  );
}

export default App;

I created this code sandbox here: https://codesandbox.io/s/restless-butterfly-brh7fk?file=/src/App.js

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If you clear the console log, and change the dropdown, you will notice that getCityParameter is called 3 times when I would expect it to be called once.

This seems to be a pretty low-level React feature and I apologize for the "not-so-small" example – this is the best I could come up with to reproduce the behavior.

Can anyone explain?

>Solution :

In the change handler, first:

const newCityParameter = getCityParameter(newCity);

So that’s one call for getCityParameter. Then, the component re-renders because the state setter was called. This:

const [cityParameter, setCityParameter] = useState(getCityParameter());

is like doing

const result = getCityParameter();
const [cityParameter, setCityParameter] = useState(result);

The function gets called again every time the component renders, so you see it again. Finally, because you’re in strict mode:

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

The app re-renders a second time, so getCityParameter runs again, making a total of 3 times that it’s been called when the dropdown is changed.

The initial state value is only used when the component mounts, of course – which means that calling a function every time the component renders when not needed might be seen as unnecessary or confusing. If you wanted getCityParameter to not be called on re-renders, and to only be called on mount in order to determine the initial state value, use the functional version of useState. Change

const [cityParameter, setCityParameter] = useState(getCityParameter());

to

const [cityParameter, setCityParameter] = useState(getCityParameter);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading