What invokves the 2nd function call when using React Hooks?

Viewed 51

I wrote the following React exercise which uses no hooks and renders a button.

const Button = ({ onClick }) => <button onClick={onClick}>Do Nothing</button>;

const Base = () => {
  const onClickFunction = (() => {
    console.log("Creating OnClick Function");
    return () => {};
  })();

  return (
    <div className="App">
      <h1>Hello</h1>
      <Button onClick={onClickFunction} />
    </div>
  );
};

onClickFunction uses a self-invoking function, so that I can place a console.log to see the following behaviour. In this example, when Base is rendered, the message Creating OnClick Function appears only once

If I change Base to the following however, adding a hook usage:

const Button = ({ onClick }) => <button onClick={onClick}>Do Nothing</button>;

const Base = () => {
  const notUsedRef = React.useRef();

  const onClickFunction = (() => {
    console.log("Creating OnClick Function");
    return () => {};
  })();

  return (
    <div className="App">
      <h1>Hello</h1>
      <Button onClick={onClickFunction} />
    </div>
  );
};

You will see the Creating OnClick Function message twice.

This CodeSandbox illustrates what I've been seeing: https://codesandbox.io/s/dawn-forest-99clo?file=/src/App.js


  • Using React DevTools Profiler, we can see there is no rerender of this component.
  • Using <React.Profiler, it reports this component also didn't update.

I know that using React.useCallback wouldn't trigger a second invokation, however the question would still stand why we are in the situation Base is called twice.

My question is: why and what is triggering Base to be invoked when there is no need for a rerender.

1 Answers

This is due to the way React implements hooks. If you invoke any hook, even if you don't use the resulting value, you are telling React to render twice before mounting, even if the props don't change. You can substitute the usage of useRef by useState, useEffect, etc. Try below.

You can also wrap your component with React.memo. Every function defined inside the function is recreated in every render.

https://codesandbox.io/s/elastic-water-y18w0?file=/src/App.js

EDIT: Only happens during development and in components wrapped by React.StrictMode. In the words of gaearon:

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.

https://github.com/facebook/react/issues/15074

Related