💡THE BIG IDEA
State redraws the screen — that is its job. But timer ids, stopwatch ticks, previous values and DOM handles need to change QUIETLY. useRef is the escape hatch: a box on the same shelf as your state, mutable through its .current door, provably identical across renders, and provably invisible to the render cycle. Both proofs run and print.
1const box = []; let cursor = 0;
2function useRef(init) {
3 const i = cursor++;
4 if (box[i] === undefined) box[i] = { current: init };
5 return box[i];
6}
7let renders = 0;
8function Timer() {
9 cursor = 0;
10 const seconds = useRef(0);
11 renders++;
12 console.log("render #" + renders, "| seconds.current =", seconds.current);
13 return seconds;
14}
15const r1 = Timer();
16r1.current = 1;
17r1.current = 2;
18const r2 = Timer();
19console.log("same box across renders?", r1 === r2);
●You know useState: change it and the screen redraws. But some things must change WITHOUT redrawing — a ticking stopwatch value, a timer id, "what was this prop last render?". For those, React gives you an escape hatch.
useRef, built on the same shelf as lessons 1 and 8 — with two properties we will PROVE: mutating it re-renders nothing, and it is the same object every single render.
📦 Memory boxes
what the program is remembering right now
nothing remembered yet🖥️ What the computer shows
the answers the program prints out
nothing yet ▌