This is my Component:
function Test() {
const [data, setData]=useState<Array<string>>([]);
console.log('Hello:', data);
useEffect(()=>{
console.log('data: ', data)
}, [data])
const test1 = () => {
setData(data.concat('a'));
}
const test2 = () => {
setData(data);
}
return (
<>
<button onClick={test1}>Button one</button>
<button onClick={test2}>Button two</button>
</>
);
}
Everything works fine when clicking Button one
. Component does re-render and effect does run. However, what happens with Button two
is something I cannot explain:
- If clicking
Button two
right afterButton one
, the Component does re-render but effect does not run. That makes no sense since React is usingObject.is
comparison for deciding if it should re-render/run the effect. How does this comparison produce different results amonguseState
anduseEffect
? At first it decides to re-render, that means state valuedata
has changed. How is that true withsetData(data)
? Then, it decides not to run the effect, that means there is no change indata
dependency. Obviously, there is a contradiction among the above two decisions… - If clicking
Button two
for a second time (after having clicked onButton one
), then nothing happens which does make sense absolutely.
Could someone explain the above behaviour?
2
Answers
If the new state is the same as the current state, as you mentioned by
Object.is
React will skip the re-render but as mentioned in the React useState docs React might still call the component.This results in running the
console.log
with the"Hello: ", data
values.And so, React does not actually re-render the component.
We can see this with a
useEffect
with no dependency array which acccording to the React useEffect docs should run every re-render.As you can see this is not the case.
what happened is when you use
setData(data);
the Component Re-renders no matter if the Data has actually changed or not, but when it comes touseEffect
the way it compares values it takes the old values and compares it with the new ones if the values have changed it will execute what inside it otherwise it won’t, this behavior will also happen if the data is an object it will check each value inside it to decide whether the object has changed or not