skip to content

State & Reactivity

Who owns a value, how a runtime learns it changed, what equality makes the change visible, and what re-runs afterward. Interviewers start here because most update bugs trace to one of those links.

on this pageshow

explore

questions

page 1 of 2

In a component framework, what does deriving a value from state during render mean, and why is it the default?

level: juniorimportance: must knowfreq 70%

answer

  1. one source of truth
  2. recompute, do not maintain
  3. a cache can disagree; a computation cannot
  4. nothing to invalidate
  5. shrink the input before caching

basics

~20 s

Deriving means recomputing the value from current state on each render and storing nothing. It is the default because a recomputed value cannot disagree with its inputs; a cache is an optimisation for where it measurably pays.

solid answer

~40 s

A derived value is one computed from state the component can already read: a total, a filtered collection, a label, a `canSubmit` flag. Deriving it means evaluating that computation where the value is needed rather than keeping a second copy. It is the default for a correctness reason, not a style reason: a value recomputed from current state cannot be stale, there is nothing to invalidate, and the rule sits next to its use. The work is also usually trivial next to the render it happens inside. A cache is worth adding when the derivation is genuinely heavy — sorting or grouping thousands of records, building an index — and even then I would first try to shrink the input, because that removes the cost instead of adding a cache to manage.

go deeper

for a junior

Recall the definition: a derived value is computed from state, not stored alongside it. Be able to name two examples, such as a total from a list and a submit-enabled flag.

for a middle

Explain the mechanics: which unit re-evaluates, why the computation is small next to the render containing it, and what a cache adds in exchange for skipping it.

for a senior

Show judgment about when to leave the default, and demonstrate that you narrow the input before reaching for a cache. Name the measurement that justified the change.

for a principal

Frame it as a team default: computing is correct by construction, so caching should require a stated reason. Say how you keep that from becoming folklore in either direction.

A **derived value** is a value computed from other values a component can already read: a total from a list of items, a filtered collection from a collection plus a search term, a label from a status field, a boolean saying whether a form may be submitted. **Deriving** it means writing that computation and evaluating it where the value is needed, from the state as it is at that moment. Nothing extra is stored, so nothing has to be kept in step. ## Why recomputation is the default Every component framework re-evaluates *some* unit of work when the state it reads changes: a whole component function, a template expression, a compiled update block. Whatever that unit is, an expression inside it that reads state is re-evaluated with the new state at no extra cost to you. That buys the properties that matter most: - A recomputed value **cannot be stale** — it is produced from the inputs that exist when it is read. - There is **one source of truth**. The state is the fact; the derived value is a view of it, not a second fact that could disagree. - There is **nothing to invalidate**, and invalidation is where most update bugs live. A computation has no cache to get wrong. - The rule lives **next to its use**, so a reader sees how the value is produced without hunting for the code that maintains it. ## What it actually costs The instinct that recomputing is wasteful usually overestimates the work: 1. The computation runs once per evaluation of the unit that contains it — not once per state write anywhere in the app. 2. That evaluation is already doing the framework's own work: building a description of the output, comparing it against the previous one, and touching the host tree. A sum, a comparison or a short filter is small next to that. 3. The figures that decide cost are the **size of the data** and the **number of evaluations**, not the mere presence of a computation. Genuinely expensive derivations exist: sorting or grouping thousands of records, building an index, parsing, layout mathematics. Those are candidates for a cache — after the cost has been observed, not in anticipation of it. ## Derived, cached eagerly, cached lazily | Shape | When the computation runs | Main failure mode | |---|---|---| | Derived during render | every evaluation of the enclosing unit | wasted work when the computation is genuinely heavy | | Cached, recomputed on input change | when an input is seen to change | a wrong dependency set: a stale result, or a cache that never hits | | Cached, recomputed on first read after a change | only when a reader actually asks | work happens at read time, so it can land in an awkward moment | The second and third rows are the same cache with different timing. Both add a comparison of inputs, a retained result and a place for the value to drift from its inputs. That is the trade you are making when you leave the default. ## Reaching past the default When a derivation really is heavy, the options are ordered, and caching is not first: - **Shrink the input.** Deriving from the rows currently displayed instead of the whole collection often removes the cost outright, and leaves no cache behind. - **Derive once, where the inputs live**, so one computation serves every reader instead of each reader repeating it. - **Split the cheap part from the expensive part**, so only the expensive step needs a cache. - **Then cache**, with the dependency set written deliberately, and only where the saving is visible in a measurement rather than assumed. One consequence is worth knowing early: a derivation that builds a fresh collection or object on each evaluation hands a different identity to whatever reads it, even when the contents are equal — and a reader that compares by identity will treat that as a change. The comparison rules themselves are a separate subject; what belongs here is knowing that the derivation is where the new object is born, and that returning a stable result is part of designing one. ## How to answer this in an interview State the default first, then the exception. Deriving during render is correct by construction and the baseline you should have to argue your way out of; caching is an optimisation with its own failure modes, justified by a measured cost, not by the feeling that recomputation is untidy. Saying that in one breath signals that you understand which risk you are trading for which — and it is the answer most interviewers are listening for, because the opposite instinct is what fills real codebases with caches that save nothing and occasionally serve the wrong number.

  • If a derivation really is expensive, what would you try before adding a cache?
    Shrink the input first: derive from the rows actually displayed rather than the whole collection, which often removes the cost outright and leaves nothing to maintain. Then move the derivation to where its inputs live so one computation serves every reader, and split the cheap part from the expensive part so only the expensive step needs a cache.
  • Does deriving during render mean the computation runs on every state change in the application?
    No. It runs when the unit containing it is evaluated — a component function, a template expression, a compiled update block — and that happens when the state that unit reads changes. Unrelated writes elsewhere do not trigger it, which is why the cost is bounded by how often that particular unit re-evaluates.

It is the difference between reading a thermometer when you need the temperature and writing today's temperature on a whiteboard. The whiteboard is faster to read and wrong the moment nobody updates it.

saying these in an interview costs you the question

  • Assumes any recomputation is a performance bug without measuring it
  • Believes a derived value needs a cache before it can be considered fast
  • Thinks a cache is free, ignoring the comparison and the retained result
  • Cannot say what goes wrong when a computed value is maintained by hand instead
  • Claims deriving during render re-runs on every state change anywhere in the app
open as a page

In a component framework, what is an effect, and when does the cleanup it registers run?

level: juniorimportance: must knowfreq 74%

basics

~20 s

An effect is code a component framework runs after a state change so something outside the component agrees with the new state - a timer, a listener, the document title. Its cleanup runs before each re-run and once at teardown.

open as a page

When a runtime compares each new state value with the previous one by reference, why is an in-place mutation invisible?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Reference comparison asks only whether the new value is the same object as the old one. Writing into a field changes contents but not identity, so the comparison answers "same" and dependent work is skipped. A fresh copy makes it visible.

open as a page

In a component framework, where should a value live when two sibling components both need to read and change it?

level: juniorimportance: must knowfreq 82%

basics

~20 s

The lowest common ancestor of both siblings should own it: that component holds the value, passes the current value down as an input to each sibling, and passes down a function each sibling calls to request a change.

open as a page

When component state is assigned a new value, how does a UI framework find out that anything changed?

level: juniorimportance: must knowfreq 72%

basics

~20 s

Nothing announces a bare assignment. Either the write goes through code the runtime owns - a setter, a tracked handle, or an assignment a compiler rewrote - or the runtime re-checks values later at a moment it was told about.

open as a page

What does a store that lives outside the component tree expose, and what must a component do to stay in sync with it?

level: juniorimportance: must knowfreq 72%

basics

~20 s

A store exposes a read of the current value, a write that changes it, and a subscribe that notifies listeners. A component reads while rendering, subscribes when its instance is set up, re-reads once subscribed, and releases the subscription on teardown.

open as a page

What invalidates a cached derived value in a component framework, and how is its dependency set determined?

level: middleimportance: must knowfreq 66%

basics

~20 s

A cached derivation remembers its last inputs and result; a change to an input in its dependency set invalidates it. That set is either declared by hand or recorded from the body's reads. Too narrow serves stale values; unstable inputs never hit.

open as a page

How does an effect with a declared dependency list differ from one whose dependencies are tracked automatically, and what fails in each?

level: middleimportance: must knowfreq 66%

basics

~20 s

A declared list re-runs the effect when the listed values change, and silently serves stale data for any value omitted. Automatic tracking records the reactive values actually read during the run, and misses reads made conditionally or after an asynchronous pause.

open as a page

How do you update one field deep inside nested state without mutating it, and why is that cheap?

level: middleimportance: must knowfreq 72%

basics

~20 s

Replace only the objects on the path from the root to the changed field, and reuse untouched branches by reference. That structural sharing copies a few objects, not the tree, and leaves unchanged branches identity-equal so dependents still skip work.

open as a page

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%

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.

open as a page

After one state write, what work does a re-run-and-diff runtime do that a fine-grained tracking runtime avoids?

level: middleimportance: must knowfreq 76%

basics

~20 s

A re-run-and-diff runtime re-executes the owning component function and produces a whole fresh description of its output, then compares it. A fine-grained runtime walks the subscriptions recorded for that one value and re-runs only those computations.

open as a page

In a store with unidirectional flow, what does routing a change through an action and an applier buy over direct assignment?

level: middleimportance: must knowfreq 64%

basics

~20 s

An action names the change and carries its data, one applier turns it into the next state, and subscribers are notified afterwards. The gain is a single funnel: every change has a name, an order, and one place that enforces invariants spanning fields.

open as a page

A store created at module scope works in the browser but leaks data between users when the tree is rendered on a server; why?

level: seniorimportance: must knowfreq 56%

basics

~20 s

A store created at module scope is one instance per process. A browser process serves one person, so that is what the author wanted; a server process renders many requests at once, and all of them share that instance. Create one store per request instead.

open as a page

An effect subscribes to a live feed for the current room id; after two room switches, messages from old rooms still arrive. Why?

level: middleimportance: should knowfreq 58%

basics

~20 s

The effect opens a connection per run but never closes the one the previous run opened, so connections accumulate. Cleanup must run before each re-run, closing exactly the connection that run created - not only at teardown.

open as a page

In a framework that tracks reads and writes through a state handle, why do destructured copies stop updating?

level: middleimportance: should knowfreq 62%

basics

~20 s

Tracking lives on the handle, not on the value. A value copied out is a plain snapshot with no link to the handle, so later writes never reach it and nothing re-runs. Read through the handle at each use.

open as a page

Why does a fresh object built during every render read as changed to every identity check downstream?

level: middleimportance: should knowfreq 70%

basics

~20 s

Each pass allocates a different object, and an identity check compares which object it is, not what it holds. Identical contents in a new wrapper report a change, so dependency lists re-fire and children that could skip work do not.

open as a page

Why is tracking one operation with three independent boolean flags in component state bug-prone, and what shape replaces it?

level: middleimportance: should knowfreq 58%

basics

~20 s

Three independent booleans describe eight combinations when the operation has about four real states, so contradictory ones are reachable and each write must set several flags. One status field with a closed set of named values makes the illegal combinations unrepresentable.

open as a page

What must a build-time compiler see to turn state assignments into targeted UI updates, and what escapes it?

level: middleimportance: should knowfreq 48%

basics

~20 s

It must see the reactive declaration, the expressions that read it, and the assignment that writes it, inside one compiled unit. Writes it cannot analyse - through a passed reference, from uncompiled code, or via dynamic access - escape.

open as a page

In a runtime with read-time dependency tracking, what makes a read of a reactive value create a subscription?

level: middleimportance: should knowfreq 60%

basics

~20 s

The read must go through the value's handle while a tracked computation is running. The runtime knows which computation is currently executing and records an edge to it; a read with no such computation active records nothing.

open as a page

A store subscription uses a selector that builds a fresh object on each call; why does the component update on unrelated writes?

level: middleimportance: should knowfreq 58%

basics

~20 s

A subscription decides a notification is a no-op by comparing the new selector result with the previous one, usually by identity. A selector that builds a fresh object every call never returns the same identity, so every write anywhere looks like a change.

open as a page

Two derived values read one state source and a third reads both — what is a glitch, and how is it prevented?

level: seniorimportance: should knowfreq 46%

basics

~20 s

A glitch is an evaluation with one input refreshed and the other stale, producing a value no state justifies. Runtimes prevent it by settling dependents in dependency order: ordered propagation, marking dirty and refreshing on read, or batching a turn.

open as a page

A store selector rebuilds a filtered, sorted list on every notification — how do you memoise it and why might its cache never hit?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Split it: cheap input steps that pluck references, then one memoised combining step holding the filter and sort, cached on input identity. The cache never hits when an input step builds something fresh, or one entry serves differing arguments.

open as a page

A component has one effect that syncs the document title, a listener, a timer and a saved draft on every update - what is wrong?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Bundling four concerns gives them one dependency set - the union - so any single change re-runs all four, restarting the timer and re-attaching the listener, and one cleanup block that must undo every combination. Split by trigger, one effect per concern.

open as a page

A state change never appears on screen while other work re-runs producing identical output — how do you diagnose each?

level: seniorimportance: should knowfreq 58%

basics

~20 s

Capture the value at the seam across two passes and compare identity and contents as separate facts. Same identity with different contents means an in-place write; new identity with identical contents means a producer allocating each pass. Repair the producer.

open as a page

When is a shallow comparison enough at a seam, and what does a deep comparison at a frequently checked seam cost?

level: seniorimportance: should knowfreq 56%

basics

~20 s

Shallow comparison checks each top-level property by reference, which suffices under immutable updates, because a nested change forces new references up the path. A deep comparison walks the graph on every check, so its cost scales with the data.

open as a page

A value owned near the root is threaded through five components that never read it, and every keystroke re-renders most of the page; how do you decide whether the owner sits too high?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Decide from the readers, not the depth. List every component that reads or writes the value, take the lowest one containing them all, and compare it with the current owner; the levels between that only pass it along are the cost.

open as a page

A detail panel keeps the previous item's unsaved edits after the user selects a different item; who should own that state?

level: seniorimportance: should knowfreq 44%

basics

~20 s

The panel owns draft state that outlives its subject. Either stop storing it and derive the fields from the selected item, give the panel a new identity per item so the old state is discarded, or reset deliberately on selection change.

open as a page

A runtime that dirty-checks the whole component tree after every event slows as the tree grows - why, and how is the check narrowed?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Cost follows bindings compared per pass times the number of passes, not how many values changed. Narrowing means walking only subtrees the runtime was told may have changed, which requires unchanged inputs to be recognisable by reference.

open as a page

What must an adapter that bridges a foreign store into a component tree guarantee about its snapshot read?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The read must be synchronous, return the same identity until a write happens, and return a new one after a write. Otherwise the runtime either sees a change on every check and never settles, or never sees one at all.

open as a page

Your team proposes caching every derived value in the app as a standing rule — how would you evaluate that policy?

level: principalimportance: should knowfreq 38%

basics

~20 s

Answer with a cost model: each cache adds an input comparison, retained memory, a dependency set that can go stale, and review cost. It pays only where compute exceeds the comparison and inputs are stable — so cache at measured hot spots.

open as a page

showing 1–30 of 33