In React, a text input re-renders on every keystroke, yet the caret keeps its position and focus is never lost. What does React do when the element type at a position is unchanged, and which browser state survives because of it?
answer
- node object identity, not markup
- only the differing props are applied
- the browser stores state on the node
- activeElement points at something specific
- style compared declaration by declaration
basics
~20 sReact keeps the existing DOM node when the element type is unchanged and applies only the props that actually differ. Because the node is never replaced, focus, caret position, scroll offset and media playback all survive.
solid answer
~40 sWhen the type matches, React updates in place instead of rebuilding. It compares the previous props of that element with the new ones and produces a minimal set of mutations for the existing node: set the attributes and properties that changed, remove the ones that disappeared, diff the `style` object property by property, and swap event handler references. The node object itself is never replaced, so everything the browser stores on it survives — focus, text selection and caret offset, scroll position, the current value of an uncontrolled input, a `<video>` element's playback position, running CSS transitions, the document inside an `<iframe>`. Refs pointing at it stay attached and keep pointing at the same node. Then React recurses into the children and applies the same rule one level down.
go deeper
Know that a matching element type means React updates the existing DOM node instead of recreating it, and that this is why typing into an input does not lose focus.
Explain the update itself: previous props against next props, only the differences applied, style compared per declaration, children recursed into rather than set as a value.
Be able to reason from a symptom back to node identity — a lost caret, a restarted video, a reloaded iframe all say the node was replaced — and to name what structural change caused the replacement.
Treat node stability as a design constraint for anything imperative: third-party widgets, media, editors and measurement code all assume a node survives, so component boundaries must guarantee type-stable positions for them.
## The path taken when types match Reconciliation at a position starts with the element `type`. If it is unchanged, React takes the update path rather than the replace path, and the distinction is the whole reason interactive UIs work at all. For a host element, updating means React holds on to the DOM node that is already in the document and computes what to change on it. It has the props from the previous render and the props from this one, so it walks them: - props present in both with a different value are applied to the node, - props that disappeared are removed (attribute removed, or the property reset), - new props are added, - `style` is compared property by property, so changing one declaration does not rewrite the whole inline style, - event handlers are updated by storing the new function reference; React does not add and remove native listeners per render, because handlers are dispatched from a listener attached at the root container, - `children` is not treated as a value to set, it is a subtree to recurse into. For a component, updating means the same fiber is reused: its hook state stays where it is, React calls the function again with the new props, and reconciles what comes back against what the component returned last time. ## Why node identity is the point A DOM node is not just markup. The browser attaches a large amount of live state to the node object, none of which React manages: ```jsx // same node across every keystroke -> caret and focus survive <input value={text} onChange={(e) => setText(e.target.value)} /> ``` That live state includes: - **focus** — the document's `activeElement` points at a specific node; destroy it and focus falls back to `<body>`, - **selection and caret offset** inside a text field or a `contenteditable`, - **scroll position** of any scrollable element, - **the current value of an uncontrolled input**, which lives only in the DOM, - **media state** — a `<video>` or `<audio>` element's playback position, buffered data and play/pause status, - **animation state** — a running CSS transition or animation restarts from the beginning on a new node, - **the loaded document of an `<iframe>`**, which reloads from scratch if the element is recreated, - **imperative state set by a third-party library** that was handed this node. Because the type matched, none of that is touched. This is why a controlled input survives re-rendering on every keystroke: React sets the `value` property on the node it already had, and the caret is undisturbed because the node never left the document. ## Where in-place updates surprise people The rule cuts the other way too. React reuses the node when the type matches *even if you meant it to be a different thing*. Two conditional branches that both render `<input>` at the same position share one node, so whatever the browser stored on it — the typed value of an uncontrolled input, the focus ring — carries across the switch. ```jsx // same type at the same position: one node, reused {isEmail ? <input type="email" name="email" /> : <input type="text" name="nickname" />} ``` React patches `type` and `name` on the existing node rather than creating a new one, which is efficient and occasionally not what was intended. ## Text and children Text content is reconciled the same way. When a text child's content changes, React sets the node's text rather than replacing it, so surrounding nodes and their state are untouched. Only when a text child is replaced by an element, or the reverse, does the node get swapped. ## What to emphasise in an interview The strong version of this answer connects the mechanism to something observable. "React updates in place" is a claim; "the input keeps focus because the node object is the same one, and `document.activeElement` still points at it" is an explanation. Then name at least one non-obvious survivor — uncontrolled input value, video playback position, or a running transition — because those are the ones that make the difference between updating and rebuilding concrete rather than theoretical.
- If React reuses the node, why does an uncontrolled input sometimes still lose its value?Because something changed the element type or the structure at that position, so the node was replaced rather than updated. A wrapper tag that flips, a component swapped at the same slot, or a component redefined each render all take the replace path, and an uncontrolled value lives only in the DOM node that just got destroyed.
- Does React re-attach a native event listener on every render when the handler function is a new inline arrow?No. React stores the new function reference for that element and dispatches through a listener attached once at the root container, so a new inline handler each render costs a reference update, not a DOM listener swap.
- Does a ref pointing at the node change identity when props are patched in place?No — the ref keeps pointing at the same node and no attach or detach happens. Refs are only detached and re-attached when the element is actually replaced, or when the ref itself changes between renders.
saying these in an interview costs you the question
- Thinks React recreates the DOM node on every render
- Says the virtual DOM is compared against the real DOM
- Believes focus is restored by React after each update
- Claims React rewrites the whole style attribute on any change
- Assumes new inline handlers add and remove native listeners