In a component framework, what is the difference between a component's definition, a live instance, and the output it produces?
answer
- three things, three lifetimes
- recipe, live copy, description
- one definition, many instances
- state belongs to the instance
- output is a value, not nodes
basics
~20 sA definition is the reusable recipe: a function, a class or a compiled template. An instance is one live copy created where that definition is used, owning its own state. The output is the description the instance produces each update.
solid answer
~40 sThree separate things with three different lifetimes. The **definition** is authored once - a function, a class, or a template the toolchain compiles - and holds no per-use state. An **instance** is created by the runtime at the moment that definition is used at a position in the component tree; it owns that position's state, whatever it acquired, and its own lifecycle, and it lives until the position goes away. On every update the instance produces an **output description** of what should appear - a tree of element descriptors, not host nodes - and the runtime is what turns that description into real nodes. So the same definition used at two positions gives two independent instances with independent state, and the output is a value the runtime consumes rather than the interface itself.
go deeper
Be able to name the three: definition, instance, output. Remember that state lives on the instance, so the same component used in two places keeps two separate states.
Explain the lifetimes - a definition loads once, an instance lives as long as its tree position, an output lasts one update - and why values declared beside a definition leak across instances.
Reach for the distinction when diagnosing: shared mutable state sitting beside a definition, state that vanished because its position was replaced, or code that treats output as the live interface.
Decide what a shared library may keep outside instances - caches, registries, counters - and write the ownership down, because module-scope state quietly turns component reuse into coupling.
The word "component" is used for three different things, and most early confusion about component frameworks comes from collapsing them. Separating them makes almost every later rule - where state lives, when cleanup runs, why reusing a component is safe - fall out for free. ## The definition A **definition** is what you author: a function that returns output, a class with a method that returns output, or a template the toolchain compiles into one of those. It is loaded once for the whole application, and it describes three things: - the **inputs** it accepts from whatever uses it, - the **state** it will want once it is alive, - the **output** it produces for a given combination of inputs and state. A definition is not alive. It has no state of its own, no position in a tree, and no lifecycle. Anything declared *beside* it - at module scope, outside the body the runtime calls - is also created once, which is precisely why such a value is shared by every use of the definition and is a classic source of accidental coupling between unrelated parts of a screen. ## The instance An **instance** is created by the runtime when a definition is used at a position in the component tree. It is the live thing: - it holds that position's state, - it holds whatever was acquired for it - a timer, a subscription, an observer, an in-flight request, - it has a lifecycle: created once, updated many times, torn down once. Its lifetime is tied to the position, not to the definition. If the position disappears, the instance is torn down and its state is gone with it. If the same definition is used at three positions, three instances exist, each with its own state; a write in one is invisible to the other two. ## The output On each update the instance produces an **output description**: a lightweight account of what should appear - which elements, with which values, in which order, containing which children. It is a value, not the interface. The runtime consumes it: it compares the description against what is already there, decides which child instances to keep, create or tear down, and applies the smallest set of changes it can to the host. | | definition | instance | output | |---|---|---|---| | created | once, when the code loads | when the definition appears at a tree position | on every update of that instance | | how many exist | one | one per position where it is used | one per update | | owns state | no | yes | no, it is a plain value | | ends when | the application unloads | that tree position is torn down | the runtime has applied it | ## Why the distinction pays for itself 1. **State placement becomes answerable.** Per-use values belong on the instance; values that every use should genuinely share can sit beside the definition; values two positions must agree on belong above both. 2. **Reuse is safe by construction.** Putting one definition into a list a hundred times produces a hundred instances, so a hundred independent open-or-closed flags need no coordination. 3. **Cleanup has an obvious owner.** Resources are acquired by an instance and released when that instance is torn down. The definition cannot own them, because it is never torn down. 4. **Output is discardable.** Because output is a description rather than nodes, the runtime may build it, throw it away, and build it again without the user seeing anything. ## Where the models differ Runtimes disagree about how visible this machinery is. One that re-runs the whole component body on every update makes the per-update description very concrete - you can watch a new tree being built each time. One with fine-grained dependency tracking runs the body once per instance and afterwards re-evaluates only the individual expressions whose sources changed, so there may be no whole-tree description per update at all. A compile-time model turns the definition into instructions that create and patch host nodes directly, so the "description" survives only as a compiled update path. The three-way split still holds in all of them - code loaded once, an instance that is alive, per-update work whose product the runtime applies - but only the first literally hands back a tree. ## The mistakes this distinction prevents - Keeping per-use state at module scope beside the definition, then being surprised that two positions share it. - Expecting state to survive when the position it lived at is removed and later recreated. - Treating the returned output as the live interface and trying to mutate it. - Assuming "the component" writes to the screen, which makes the runtime's batching and ordering look arbitrary.
- If one definition is used at two positions, what is actually shared between the two instances?Only what lives outside the instances: the definition's own code, and anything declared at module scope beside it - a cache, a counter, a mutable object. Those are created once, so a write from one instance is visible to the other. Inputs, state, acquired resources and lifecycle are per-instance.
- Why does the runtime, rather than the component, turn output into host nodes?Because a description can be compared with the previous one, batched with other work, reordered, discarded, or applied to a different kind of host. If every component wrote nodes itself there would be nothing to compare, no single owner of update order, and no way to reuse the instances that are already correct.
- What happens to an output description after the runtime has applied it?It has no further job. Some runtimes retain the last description to compare the next one against; others apply it and drop it; a fine-grained runtime may never build a whole-tree description in the first place, updating only the expressions whose sources changed. Either way it is not state you can read back.
The definition is a blueprint, each instance is a house built from it with its own occupants and its own wiring, and the output is the work order the builder is handed for this round of changes.
saying these in an interview costs you the question
- Says the definition itself stores the state
- Thinks producing output creates host nodes directly
- Believes using a component twice shares one instance
- Cannot say when an instance begins and ends
- Treats module-scope values as per-instance state