In React, why does changing the ref value not trigger multiple re-renders? Let's discuss what happens under the hood in React. 1. React initializes the ref object with initialValue defined in the code. 2. The ref object is saved in the memoizeState property of the hook node in the linked list of hooks. 3. The hooks linked list is internally managed by React with the order in which we define hooks in the component's code. 4. If useRef is the first hook, its data will get saved on memoizedState property of an internal structure called currentlyRenderingFiber which refers to the fiber node of the component currently being rendered. 5. Otherwise, the work-in-progress pointer will add useRef to the hooks linked list as per the order of the hooks in the code. 6. WorkInProgress is an internal pointer to traverse the hooks linked list, add a new hook during the first render, or reuse/clone existing ones during re-rendering. 7. React maintains hooks in a linked list so that the order of hooks doesn't get changed. When rerender happens 1. The React updateRef method is called internally, and the WorkInProgress pointer traverses through the hooks linked list, finds, and returns the same memoizedState node against which ref was initially defined. Points no. 4, 5, and 6 might feel quite overwhelming; I will discuss these in the coming days. I do a deep dive into foundational concepts & how things work under the hood. You can consider connecting with or following me, Ali Raza, to get along with the journey. #react #javascript #frontend #nextjs
Excellent deep dive. It’s rare to see someone explain the inner workings of useRef and React’s hook linked list so clearly. I’ve always found it fascinating that refs don’t trigger re-renders because React stores them in the fiber’s memoized state outside the reconciliation flow — meaning updates to .current mutate the object directly rather than scheduling a render. This subtle design choice makes refs perfect for storing mutable values like DOM nodes or previous state without affecting the component’s lifecycle. Looking forward to your next breakdown on how the work-in-progress pointer manages hooks internally.
Hmm, now am intrigued to look further into how linkedlists are being used here in react Thanks for sharing Ali Raza
quintessential 💫
Great!
Because refs live outside React’s render cycle. A ref is just a mutable container whose .current is read and written imperatively; React doesn’t track it for change detection. Under the hood, useRef creates a stable hook node once, stores the object on the fiber’s hooks list (memoizedState), and then returns the same object every render. When you mutate .current, you’re changing a field on that same object, no new hook node, no new identity, no state queue dispatch, so React has nothing to schedule. By contrast, useState enqueues an update, compares identities/values, and schedules a re-render. Refs are intended for escape hatches (DOM handles, instance vars, caches), not for driving UI; if the UI should update when a value changes, keep it in state or derive it from state/props.
Nice work
The question is bad, even useState value does not change on re-renders, if there are multiple useState are used and among these only one who triggers the re-render get the updated value, other useState variable preserves their value on re-renders. Good question can be why updating ref value does not trigger re-render.