skip to content

A component copies an incoming input value into its own state when created; what breaks when the parent later passes a different value?

level: middleimportance: must knowfreq 66%

answer

  1. initial means initial
  2. snapshot, not a link
  3. read the input, do not mirror it
  4. a draft is owned, not copied
  5. cache with no invalidation rule

basics

~20 s

Nothing updates the copy. An initial value is read once when the state is created, so the component keeps rendering the old snapshot while the parent holds the new value: two truths for one concept.

solid answer

~50 s

Initialising state from an input captures a **snapshot**, not a link. The initial value is used when the cell is created and is not consulted again, so a later value from the parent lands in the input while the component still renders its copy. That is the classic "works on first load, wrong after the parent changes" bug. The first question to ask is whether the cell is needed at all: if the component only displays the value, read the input directly — stored state that mirrors something you already receive is a second truth that can fall behind. The copy is legitimate when the component genuinely owns an edit the parent has not accepted yet, such as a draft. Then it is not a mirror, and you owe an explicit answer to one question: when the input changes underneath the draft, does the draft win, reset, or block?

go deeper

for a junior

Remember that a starting value is read once. If a component must follow a value the parent keeps changing, it should read the input rather than keep its own copy of it.

for a middle

Explain the mechanism — the cell is seeded, not linked — and name the fixes in order: do not store it, lift the change to the owner, or own a real draft with a stated rule for input changes.

for a senior

Demonstrate the diagnosis from the symptom (right on first load, stale afterwards) and treat syncing from a watcher as a design decision needing a conflict rule, not a patch.

for a principal

Push on the invariant: a stored value that must equal another is a cache your team has to maintain forever. Decide as a matter of convention which values may be duplicated at all.

## Stored versus derived, and where a copy fits Every value a component renders comes from one of three places: state it owns, an input it was handed, or a computation over those. Storing a value is a commitment — you now own it, you must keep it correct, and nothing else may assume it matches anything. Deriving a value commits to nothing: it is recomputed from whatever the current truth is, so it cannot be stale. Copying an input into state looks like storing but is meant as deriving, and that mismatch is the bug. ## Why the copy goes stale An initial value is, by construction, initial. The component is created, the cell is given a starting value taken from the input at that moment, and from then on the cell's only inputs are writes. The parent's later value goes into the input, which the component may not even read any more. Both values are live, both are internally consistent, and the screen shows whichever one the markup names. Runtimes differ in the shape of the trap, not in the trap itself: where a component function re-runs on every write, the initialiser expression is re-evaluated but its result is deliberately discarded after the first run, which is why the code reads as if it should update; where reads are tracked individually, assigning a tracked value into a new state cell copies the value out of tracking, so later changes reach nothing; where the reactive declaration is recognised at compile time, only what is declared derived stays linked, and a plain state declaration seeded from an input is not. ## Symptoms an interviewer will recognise - The component shows correct data the first time and stale data after the parent changes it. - It becomes correct after an unrelated action that happens to recreate the component. - There is a watcher whose whole body copies an input into state. - Two fields must "agree", and a bug report says they sometimes do not. - A list row keeps a neighbour's values after the list is reordered or filtered. ## The four responses, and when each is right | Response | What it means | Right when | |---|---|---| | Do not store it | Render the input, or compute from it | The component only displays or formats the value | | Lift the change | The parent owns the value; the child requests edits | Anyone else needs to see the edit as it happens | | Own a real draft | The child's cell is new state, not a mirror | Edits are provisional until committed, and only this component cares | | Copy in on input change | A watcher writes the input into the cell | Rarely — a last resort, and it needs a rule for conflicts | The last row deserves its bad reputation. Syncing a copy from a watcher means the value is written twice per change, there is a moment where the rendered value is the old one, and two writers now exist: the parent's change and the user's edit. The question "what if the user typed while the parent's value changed?" has no default answer, and code that syncs silently answers it by accident — usually by discarding the user's work. ## When the copy is correct A draft is the honest case. A form that lets the user edit and then save is *supposed* to hold a value that differs from the parent's: that difference is the feature. What makes it correct is that the component is the **owner** of the draft, not a mirror of the input, and that the relationship to the input is stated: 1. The input is the starting point for a new draft, and after that it is not the draft's source. 2. When the input identity changes — a different record is being edited — the draft must start over, either because the instance is replaced or because something resets it deliberately. 3. When the input's value changes for the *same* record, the product has to choose: keep the user's edit, overwrite it, or surface the conflict. Silence here is what produces "my change vanished". ## The general rule Prefer derivation over duplication, and where you must store, be explicit that you own it. The tell you can carry into any codebase: a state cell whose value is supposed to equal something the component already receives is a cache with no invalidation rule, and a cache with no invalidation rule is a stale value waiting for a bug report.

  • How do you decide whether a value should be stored at all?
    Ask whether it can be computed from what you already have. If yes, compute it — a derived value cannot go stale. Store only what nothing else can tell you: a user's choice, a draft not yet committed, a position or toggle the component itself invented. Anything you store, you have promised to keep correct.
  • A watcher copies an input into state and the reviewer objects. What are you asked to justify?
    Three things: why the value must be stored rather than read, which writer wins when the input changes while the user is editing, and what happens on the extra pass where the component renders the old copy before the watcher runs. If you cannot answer the second, the copy is not ready to merge.

saying these in an interview costs you the question

  • Expects an initial value to keep tracking the input it came from
  • Adds a watcher that copies inputs into state as the routine fix
  • Says every copy of an input into state is a bug, including deliberate drafts
  • Stores a formatted or filtered version of a value it already receives
  • Cannot say who wins when a draft and a fresh input disagree
  • Calls the stale copy a caching optimisation