0

So after working with react in the past year, i managed to understand its powers and caveats, and how to avoid unnecessary renders.

Yesterday i was playing with some code and came across an issue i didnt see before, and got a little confuse.

import React, { useCallback, useState } from "react";

let renders = 0;

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount((c) => c + 1);
  }, []);

  renders = renders + 1;

  console.log("Counter Render");

  return (
    <div>
      <button onClick={increment}>increment</button>
      <h2>renders: {renders}</h2>
      <h4>Count: {count}</h4>
    </div>
  );
};

export default React.memo(Counter);

in the above code i added a simple counter, on every click i am setting a new state, which cause a re-render, showing "Count: 1" on the screen and one "Counter Render" log in dev tools - just like i expected.

The weird part comes from the renders variable, which i initiate with the number 0 ( outside the component, offcourse ) and increment on every render of the component. i would have expect the value here will also be 1 but that is not the case, every time i click the button the value of "renders" grows by 2, even though the "Counter Render" log show once each time.

Here is a the Sandbox example

can anyone explain what am i missing here ?

ishay m
  • 179
  • 11
  • 1
    I recently answered a question regarding this behaviour. The answer covers content from the official docs. Kindly see it - https://stackoverflow.com/questions/67709551/generators-are-called-more-than-expected-in-react/67710196#67710196 – Lakshya Thakur May 28 '21 at 05:52
  • I think it is because of scope of variable. If you move renders variable inside counter then it should behave as you expected. And as we are not changing state for renders variable then it should show same value no matter how many increment you do on counter. – Ankit Garg May 28 '21 at 06:00
  • 2
    @AnkitGarg If `renders` was moved *into* the `Counter` component then it would be redeclared each render cycle. It would always render `0`. – Drew Reese May 28 '21 at 06:02

1 Answers1

2

You're running in React's Strict Mode (since your app is wrapped in <StrictMode>).

Strict Mode may render components multiple times to make sure you're not doing naughty things such as relying on render counts – which you now are. ;-)

AKX
  • 152,115
  • 15
  • 115
  • 172
  • but how come the renders variable incremented twice but the console.log that comes right after it runs only once ? this is the part i dont understand – ishay m May 28 '21 at 06:06
  • @ishaym Oddly enough, if you `console.log("COUNTER", renders, count);` you see counts "1 0" "3 1" "5 2"... the renders still goes up by 2, but it's on the odd numbers. My basic advice is don't trust unintentional side-effects, they are unreliable for anything. Stick to using component lifecycle. – Drew Reese May 28 '21 at 06:35
  • will never trust them, just tried to figure this out, thanks anyway (: – ishay m May 28 '21 at 09:22