react: React.StrictMode combined with useState causes component to render twice

Do you want to request a feature or report a bug? Bug (maybe)

What is the current behavior? If wrapped in React.StrictMode and a function component contains a call to useState, the function (render) is called twice - even if the state setter is never called.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. https://codesandbox.io/s/lyw9514j4q (please see console)

What is the expected behavior? I would expect it to only render once.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React? 16.8.3 in Chrome on macOS Mojave; requires hooks so not tested with previous versions.

This may be related to https://github.com/facebook/react/issues/12961 - but note that nowhere am I setting state (only initializing it).

If this is expected behavior please feel free to close. Thank you!

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 34
  • Comments: 22

Commits related to this issue

Most upvoted comments

It’s an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.

Sorry, I know this was closed, but you say

We only do this for components with Hooks…

but if your component uses a class – even if it’s stateless – it also renders twice. Threw me for a loop today trying to figure out why my component wasn’t working properly.

export default class App extends React.Component {
  render() {
    console.log('this logs twice with React.StrictMode');
    return null;
  }
}

Hey @nermand

(I think) the trouble you’re seeing is because state.items.push in your reducer modifies the array in place. This means you’re trying to modify a piece of React state outside of the setter for that state.

The use of .push can be replaced with a use of .concat. Sandbox with the fix

Notice that reducer(state, event) still gets called twice for each click (with the same objects for state and event in each call), but it is no longer an issue since state is no longer changed between those two calls. As mentioned above, this is a deliberate behaviour of strict mode to help us notice issues like this.

Strict Mode always did this for classes. That’s the first thing it ever did. 😃

The question was about function components. So I explained that for function components, this was only on when they contained Hooks. In any case, we’ve changed that too already so it will fire for all function components soon.

react component render twice bug❓

next.js

import React, {
  useEffect,
  useRef,
} from "react";
import { createRoot } from 'react-dom/client';

export default function Home() {
  const log = console.log;
  log(`v18 createRoot =\n`, createRoot);
  let root = useRef(null);
  useEffect(() => {
    // v18
    console.log(`root =`, root)
    console.log(`root.current =`, root.current)
    if(!root.current) {
      const App = document.getElementById('v18-app');
      root.current = createRoot(App);
      root.current.render(<h1>Develop. Preview. Ship. 🚀 React v18 🆕</h1>);
    }
  }, []);
  return (
    <div id="v18-app">...loading</div>
  )
};

image

Cheers @jaredkhan, that explains it.
We just need to keep treating every piece of state immutable and everything should be fine.
Thanks!

demo link Any way to fix this issue?

The old[id] assignment is modifying the array being passed in. Instead, modify a copy of that array:

  setTrades((old) => {
    const updated = [...old]
    updated[id] = {
      count: old[id].count + 1,
      active: !old[id].active
    }
    return updated
  })

Ohh. Why didn’t you mark this in the documentation for StrictMode?

🙆‍♂️ Dan’s answer explained my confusion But I still think it may be an added burden on the mind