Why does my react app render twice??

Why does my react app render twice??

...and how to stop it

Ever tried to print out to the console while building a React app, and noticed you have two logs displayed each time? This got me wondering at first, as I thought it was a bug. Turned out it is intentional.

The reason for this behavior is that your app is running in Strict mode. This is an intentional measure by the React team to ensure your components are pure functions. A pure function is a programming concept that specifies a function, given the same arguments, should produce the same output - and hence, not break or affect anything outside the function. So your React app renders twice during development, to detect such a bug in your development environment.

This feature, while useful, can sometimes be annoying. For example, when using useEffect to read an API and update the initial component state. You notice the useEffect runs twice even with an empty dependency array. This can have unintended results depending on your starting logic.

Here're two ways to stop this behavior:

  1. Delete <React.StrictMode> around your <App/> in the index.js file.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    //Default
  <React.StrictMode> 
    <App />
  </React.StrictMode>
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

This stops the double renders. You can still Wrap your components with <React.StrictMode>, if you wish to utilize its benefits on such components.

  1. A combination of useState() and useRef()

This is my recommended method as it does not require one to remove <React.StrictMode> hence, keeping the debug feature. It utilizes useState() and useRef() hook to check whether the application has been rendered before. That way, we can ensure our starting code runs once.

  const hasLoadedBefore = useRef(true)
  useEffect(()=> {
    if(hasLoadedBefore.current){
      //your initializing code runs only once
      console.log("Effect ran")
      hasLoadedBefore.current = false;
    } else{
      //subsequent renders
    }
  }, [])

Hope this helps you. Feel free to drop a comment if your issue persists. Thanks for reading ❤️