React 18 - Strict Mode and "everything renders twice?!?!"

A lot of my side projects were running on older versions of React (mostly 16 and 17). I recently upgraded one of my projects to React 18 and ran into a few issues. One of the issues was that everything was rendering twice. I had a look at the React 18 release notes and found that this is a deliberate change in React 18. From the React v18 docs:

StrictMode lets you find common bugs in your components early during development.

Strict Mode enables the following development-only behaviors:

- Your components will re-render an extra time to find bugs caused by impure rendering.
- Your components will re-run Effects an extra time to find bugs caused by missing Effect cleanup.
- Your components will be checked for usage of deprecated APIs.

I also found this interesting note (apologies for the legacy doc reference):

In the future, we’d like to add a feature that allows React to add and remove sections of the UI while preserving state. For example, when a user tabs away from a screen and back, React should be able to immediately show the previous screen. To do this, React will support remounting trees using the same component state used before unmounting.

This feature will give React better performance out-of-the-box, but requires components to be resilient to effects being mounted and destroyed multiple times. Most effects will work without any changes, but some effects do not properly clean up subscriptions in the destroy callback, or implicitly assume they are only mounted or destroyed once.

To help surface these issues, React 18 introduces a new development-only check to Strict Mode. This new check will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount.

So, the extra render is a feature, not a bug. It's designed as a way to help you find bugs in your components early during development. (And if you want to disable this feature, you can remove the StrictMode component from your app.)

Production builds will not have this extra render. It's only in development mode. (I can feel some subtle console.log statements being added to my codebase to check for this..!)

The moral of this story is that I should probably read release notes etc. before upgrading my projects. I'm sure I'll find more surprises in React 18 as I continue to work with it!