Summary
A React state array was being updated incorrectly because the update logic replaced every element instead of updating one specific index. The root issue was mixing DOM inspection (childNodes) with React state updates, causing non-deterministic behavior and full-array overwrites.
Root Cause
The update function:
setTips((tips) =>
tips.map((x, i) => (+x !== e.target.childNodes[i].id ? newTip : x))
);
relies on:
childNodes[i].id— which does not correspond to the array index- A comparison that evaluates true for all elements, causing a full overwrite
- Mutating logic that depends on DOM structure instead of React state
This results in every element being replaced with the new tip value.
Why This Happens in Real Systems
- DOM-based indexing is unreliable — React does not guarantee DOM order matches array order.
- Mapping with the wrong condition causes all items to match.
- State updates must be pure — mixing DOM queries breaks purity.
- Multiple state updates in one event (
handleAddTip+handleUpdatedTips) cause race conditions.
Real-World Impact
- Users see all tips change at once, breaking the calculator.
- Debugging becomes difficult because the DOM and state become out of sync.
- The UI behaves inconsistently depending on render timing.
Example or Code (if necessary and relevant)
A correct update pattern uses index-based updates, not DOM inspection:
function updateTipAtIndex(index, newTip) {
setTips((tips) =>
tips.map((tip, i) => (i === index ? newTip : tip))
);
}
And the select component must pass the index:
updateTipAtIndex(i, +e.target.value)}>
This ensures only the intended element is updated.
How Senior Engineers Fix It
- Never read from the DOM to determine state.
- Pass explicit indices or IDs through props.
- Use pure functions for state updates.
- Avoid double-updating state in one event handler.
- Normalize data flow so each component knows its own index.
A senior engineer rewrites the flow:
- Each guest row receives its own
index - The select calls
onChange(index, newValue) - The parent updates only that index
Why Juniors Miss It
- They assume DOM order equals array order.
- They try to “inspect” the DOM instead of trusting React’s data flow.
- They misunderstand how
mapconditions work. - They attempt to update state twice in one event.
- They don’t yet recognize that React state must be the single source of truth.
If you’d like, I can also generate a corrected full React component showing the proper parent/child state flow.