Hint
Use ref when you need a mutable value that doesn't affect rendering (previous value, interval ID, abort controller). Use state when the value affects what's displayed.
let stateRenders = 0;
let refRenders = 0;
// Simulates useState — update triggers re-render
function withState() {
let count = 0;
function setState(v) {
count = v;
stateRenders++; // re-render
}
return { getCount: () => count, setState };
}
// Simulates useRef — update does NOT trigger re-render
function withRef() {
const ref = { current: 0 };
function setRef(v) {
ref.current = v;
// NO re-render
}
return { getRef: () => ref.current, setRef };
}
const s = withState();
const r = withRef();
s.setState(1); s.setState(2); s.setState(3);
r.setRef(1); r.setRef(2); r.setRef(3);
console.log(stateRenders);
console.log(refRenders);
console.log(s.getCount());
console.log(r.getRef());3 0 3 3
Explanation: Each setState triggers a re-render (3 total). Ref mutations never trigger re-renders (0). Both hold the latest value (3).
Key Insight: Use ref when you need a mutable value that doesn't affect rendering (previous value, interval ID, abort controller). Use state when the value affects what's displayed.