React SideEffect out of useEffect hook

Viewed 208

the effects (increment the value of r and log it) works as expected within the useEffect hook

import React from "react";

let r = 0;

export default function App() {
  const [state, setState] = React.useState(false);

  function handler() {
    setState(!state);
  }

  React.useEffect(() => {
    r += 1;
    console.log("rendering:-", r, " times");
  });

  return (
    <>
      <button onClick={handler}>render</button>
    </>
  );
}

but outside of useEffect hook the effects work unexpectedly. value of r increments by 2 rather than 1

import React from "react";

let r = 0;
export default function App() {
  const [state, setState] = React.useState(false);

  function handler(params) {
    setState(!state);
  }

  r += 1;
  console.log("rendering:-", r, " times");

  return (
    <>
      <button onClick={handler}>render</button>
    </>
  );
}

but why??? could someone explain me please.....

2 Answers

the function body was actually invoked 2 times for the strictMode rapper in index.js

<React.StrictMode>
    <App />
</React.StrictMode>

according to the React doc

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

r is still incremented by 1, however

Note:

Starting with React 17, React automatically modifies the console methods like console.log() to silence the logs in the second call to lifecycle functions. However, it may cause undesired behavior in certain cases where a workaround can be used.

You can read more on that here: detecting-unexpected-side-effects

Here's a code example which shows, that r is incremented by 1:

import React from "react";

let log = console.log
let r = 0;
export default function App() {
    const [state, setState] = React.useState(0);
    console.info('render');

    function handler(params) {
        setState((prevState) => prevState + 1);
    }

    r+=1;
    log("rendering:- r=" + r);
    log("rendering:- state=" + state);

    return (
        <>
            <button onClick={() => handler()}>render { state }</button>
        </>
    );
}
Related