Ok, I think I got the answer, but I would like to be corrected if I'm wrong:
So for this to make sense we need to understand 3 things:
- Garbage collection
- Primitive vs References
- How equality comparisons work
First, to address my previous statement:
I want to know why this is the behavior of objects (array, functions,
objects) declared inside functions as opposed to values(strings,
numbers, booleans, etc.) that seem to maintain their place in memory
and aren't being created from scratch on every function call.
Both primitives and references are created from scratch on every function call due to garbage collection, for more info check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
Primitives are saved into the stack and objects are stored in the heap and the object gets "pointer" to the location in the heap. More on that in this video
The trick with the dependencies array in useEffect
has to do with how equality works in JavaScript, a great article about this tell us that:
- If both operands are numbers and have the same value, they are
strictly equal
- If both operands are strings and have the same value,
they are strictly equal
- If both operands have reference to the same object or function, they
are strictly equal
So if we have:
function App() {
const num = 1;
const arr = [1, 2, 3];
const [state, setState] = React.useState(1);
React.useEffect(() => {
console.log("updated by change of num");
}, [num]);
React.useEffect(() => {
console.log("updated by change of arr");
}, [arr]);
return (
<button onClick={() => setState((prev) => prev + 1)}>
increase {state}
</button>
);
}
The dependency array doesn't care if num
has the same location in memory (which it doesn't due to being new in each function call) as the equality only checks for type and value, but it does care the place in memory for objects as for them to be equal they need to have the same reference.
Hope this is clear!