Many developers have implemented a similar functional component and have seen this behavior. Some have even opened a bug report in the official React repository.
The reason why this happens is an intentional feature of
React.StrictMode. It only happens in development mode and should help to find accidental side effects in the render phase.
What is happening behind the scenes?
The main reason is
React.StrictMode which was introduced in version
16.3.0. Back then it only could be used for class components. With the release of
16.8.0 it is also applied for hooks.
"StrictMode is a tool for highlighting potential problems in an application. Like Fragment, StrictMode does not render any visible UI. It activates additional checks and warnings for its descendants." ‒ from official React Documentation
React.StrictMode currently helps you with:
- Identifying components with unsafe lifecycles
- Warning about legacy string ref API usage
- Warning about deprecated findDOMNode usage
- Detecting unexpected side effects
- Detecting legacy context API
For more information about
In most cases, it will throw an error message into the browser console log. It fails to automatically detect render side effects as they often can be non-deterministic behavior.
To detect side effects the following functions are invoked twice:
- Class component constructor, render, and shouldComponentUpdate methods
- Class component static getDerivedStateFromProps method
- Function component bodies
- State updater functions
- Functions passed to useState, useMemo, or useReducer (any Hook)
Why were my components rendered twice?
The mechanism by which your components are rendered twice is as thus:
On render, the component will make the first mount.
Then react will unmount to make checks on how your code handles unmounts which is very useful for cases where you have subscriptions to APIs that need to be cleaned up to avoid memory leakage and other performance issues.
And finally, the component is mounted a second time.
Why should I use React.StrictMode?
Obviously, that re-rendering thing is definitely not a bug or something related to the library's render mechanism. On the contrary, it is a debugging mechanism provided by React.
Well, I personally think the react strict mode makes for better code writing and improved software development practices, even as I won't deny the fact that I felt like it impacted my development experience in the beginning.
How to disable strict mode
if you decide to disable the strict mode in your project, it's quite easy. If you bootstrapped your project with the create-react-app command then in the index.js file you will most likely find a React.StrictMode component wrapping your App component. You can just delete the component's open and close tags and voila.
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( // react strict mode is on by default, so we need to turn it off <React.StrictMode> <App /> </React.StrictMode> );
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( // now react strict mode is off <App /> );
This behavior definitely has some performance impact, but we should not worry since it takes place only in development and not in production.
That is why we managed to reproduce double-rendering only in development for a function component that was using React.useState. Cheers!!