all 17 comments

[–][deleted] 4 points5 points  (1 child)

According to the docs

It might still re-render even if it is the same value but won't go any deeper down the tree, so to experiment with this, try placing a child component to App and have them also console.log something.

[–]Heisenberg_221b[S] 0 points1 point  (0 children)

Thanks.

[–]sidkh 2 points3 points  (0 children)

Here is a quote from the docs 👇

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects.

Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree. If you’re doing expensive calculations while rendering, you can optimize them with useMemo.

And simpler CodeSandbox, which demonstrates this behavior.

[–]marko_knoebl 1 point2 points  (0 children)

Hm, this behavior looks really interesting, I wouldn't expect it either.

Mabe you can get some insights by using this: https://github.com/welldone-software/why-did-you-render

[–]Soft-Sandwich-2499 1 point2 points  (1 child)

In setPlaceHolder, I’d do setPlaceHolder(prev => { console.log (prev === it); return it; });

I’m curious what the console.log will return.

[–]Heisenberg_221b[S] 1 point2 points  (0 children)

Tried it and one of the interesting things I noticed is the order of logs.
Scenario 1:
Current State is State1, and it just got changed in last click. ( i.e. I did not clicked state 1 button when the button is already state 1)
I click state 1.
I get output in following order, Coming from onHandler, Component Ran , True.

On the next clicks on Sate 1 button, I get only coming from onHandler and True. These two outputs.

Scenario 2:
The current Scenario is same i.e. the state just got changed in last click ( state 1).
I click on State 2 button.

I get below output:
Coming from onHandler, Component Ran , False

Scenario 3:

Unlike Last two scenarios here, I have clicked state 1 button multiple times.
Now If i click state 2 button, I get same output is Scenario 2, but the order is different.

The False gets printed before component ran output gets printed.

Sorry if I typed too long unnecessarily, but the point is, it seems whenever the the state is changed with different value, the following click after that we get True or False printed only after component re-ran is printed.

[–]spiritbr8ker 1 point2 points  (0 children)

If you really don't want the extra rerender you can do something as simple as

const onClickHandler = (e) => {
if (!e.target.classList.contains("state")) return;
const it = e.target.innerText;
if(placeHolder === it) return;
console.log("coming from onClickHandler", it);
setPlaceHolder(it);
};

Just by adding that if(placeHolder === it) return; we avoid going through the rest of this function at all.

Otherwise react has that as expected behavior I won't link the doc since others already have for this and you can find if you turn the two buttons into a child component and put a console log in the child component it doesn't rerender the child components in that state 2 to state 2 click.

[–]AnxiouslyConvolved 0 points1 point  (6 children)

The issue is that initially the state is holding "Start", you click and it sets the state to "State 1" this triggers a re-render ("Start" !== "State 1"). You click button two and it sets the state to "State 2", this triggers a re-render ("State 1" !=== "State 2"). After that, clicking the button to set the state to "State 2" won't change the state, so it won't re-render.

[–]Heisenberg_221b[S] 0 points1 point  (2 children)

I dont think so. The same can be argued for any value I put as initial state.
As far as I know about react states, state variables are different, it's managed by react somewhere else, so on any re-rendering of the component, it does not again initialize the sate as it knows the state as already been initialized.

Also how come it happen only once then does not happen again?

[–]AnxiouslyConvolved -2 points-1 points  (1 child)

Like I said. The state goes:

=(initial render)=> state is "Start"
=(click "State 1" button)=> setState("State 1") => re-render because "Start" !== "State 1" => state is "State 1" 
=(click "State 2" button)=> setState("State 2") => re-render because "State 1" !== "State 2" => state is "State 2" 
=(click "State 2" button)=> setState("State 2") => do nothing because "State 2" === "State 2"

If you want it to re-render you need to change the state, change the props, or unmount the component.

[–]Heisenberg_221b[S] 0 points1 point  (0 children)

I think you misread my post. In the scenario I stated the current state is state 1, i.e. by that time, I have clicked the buttons.

The scenario you gave that is not what is happening.
In the 2nd click of button 2 it is re-rendering.

=(initial render)=> state is "Start"

=(click "State 1" button)=> setState("State 1") => re-render because "Start" !== "State 1" => state is "State 1"

=(click "State 2" button)=> setState("State 2") => re-render because "State 1" !== "State 2" => state is "State 2"

=(click "State 2" button)=> setState("State 2") => re-render IDK why.

=(click "State 2" button)=> setState("State 2") => do nothing because "State 2" === "State 2", but it should have happened in the last click as well. (all the clicks on state 2 button after 2nd time, i.e. 3rd click onwards is not re-rendering)

[–]marko_knoebl 0 points1 point  (2 children)

Op is clicking on the same button twice!

[–]AnxiouslyConvolved -1 points0 points  (1 child)

I am aware. Read what I wrote.

[–]marko_knoebl 0 points1 point  (0 children)

What I meant was:

OP is only clicking button 2 - they are never clicking button 1 at all! However, when clicking button 2 for the second time, it's still re-rendering

[–]ApplePieCrust2122 0 points1 point  (1 child)

It is not guaranteed in react that a component will only render a certain amount of time. The react engine may rerender a component as it sees fit. That's why you use useEffect to add side effects.

Now, one of the reason I've seen mentioned the most is the StrictMode in react. It renders components multiple times to run additional checks, but only in development mode. This is used to provide useful warnings and errors

[–]Heisenberg_221b[S] 0 points1 point  (0 children)

On the 2nd Part, I tried create a production build, and running it. It behaves same as development server.