Across a component instance's creation, update and teardown phases, which work belongs in each and why?
answer
- count how often it runs
- once, many, once
- acquire on create, release on teardown
- updates describe, they never acquire
- once means once per instance
basics
~20 sCreation runs work that must happen once per instance - initial state, acquisitions, and the registration of their releases - and produces the first output. Updates only derive output from current inputs and state. Teardown runs the registered releases.
solid answer
~50 sThe rule is a run count. **Creation** happens once per instance: establish initial state, acquire anything external such as a subscription, an interval, an observer or a request, and register how each of them is released. **Updates** can run many times - on any input or state change, and under some runtimes more often than the user-visible changes suggest, with some runs discarded before anything reaches the screen - so per-update code must be cheap, repeatable and free of side effects; its job is to describe output from the current inputs and state, not to acquire or mutate. **Teardown** happens once and runs the registered releases. Work that must reach outside the instance after an update is scheduled through the runtime's own post-update mechanism instead of being done inline while output is produced, so a repeated or abandoned update cannot perform it twice.
go deeper
Know the three phases by name and the direction of the pairing: set up in creation, undo in teardown. Never put one-time work in code that runs on every update.
Explain the placement rule - how often does this phase run - and defend why per-update code has to be cheap, repeatable and free of side effects.
Find the misplacements in review: duplicated subscriptions, initial state recomputed over live state, acquisitions with no registered release, per-update code that counts.
Own the convention the codebase is reviewed against, and set the line on how much per-update cost is acceptable before a derivation is cached, since phase discipline is what makes teardown trustworthy.
Almost every "where does this code go" question reduces to one number: how often does this run? Creation runs once per instance, the update phase runs an unbounded number of times, teardown runs once. Put each piece of work where its run count matches, and the component becomes predictable. ## The three phases 1. **Creation.** The runtime has decided this definition belongs at this position and makes an instance for it. Initial state is established here, and anything external is acquired here - a subscription, an interval, an observer, a request - each paired with a registration of how it is released. The instance then produces its first output. 2. **Update.** Something the instance depends on changed: an input from above, its own state, or an ambient value provided by an ancestor. The instance produces output for the new values. This phase runs many times over the instance's life, and not every run necessarily reaches the screen. 3. **Teardown.** The position is going away or is being replaced. The registered releases run and the instance's state is dropped. ## The placement rule as a table | work | phase | why there | |---|---|---| | establishing an initial value | creation | it is a starting point; recomputing it each update would overwrite everything that happened since | | subscribing to an external source | creation | one subscription per instance, so repeating it multiplies deliveries | | starting a timer or a polling loop | creation | the same duplication argument, plus a single handle to cancel | | deriving a value from current inputs | update | inputs change over time, so the derived value has to follow them | | an expensive derivation | update, cached by its inputs | correctness wants the update phase, cost wants the cache | | cancelling, unsubscribing, aborting | teardown | the exit is the only place that knows the instance is finished | ## Per-update code must be repeatable Treat the update phase as something that may run more often than you expect, in any order relative to sibling instances, and sometimes for nothing. That implies a short list of properties: - **No side effects.** Nothing observable outside the instance - a request, a write to a shared store, a message - belongs inline in output production. - **No acquisition.** Anything that needs releasing must not be created here, because the phase has no matching "once" to pair with. - **No mutation of what it reads.** Writing to the state or inputs being read while producing output makes the result depend on how many times the phase ran. - **Cheap.** It sits directly between a user action and the screen. - **Deterministic for the same values.** Two runs with the same inputs and state should describe the same output. ## What "once" actually promises "Setup once" means once **per instance**, not once per position and not once per application. If the runtime replaces the instance at a position, the new instance gets its own creation pass and its own acquisitions, and the old one gets its teardown. That is why creation is the right home for per-instance resources and the wrong home for anything meant to be process-wide: a process-wide cache created in creation is created again for every instance. ## Where reactivity models change the picture The three phases are universal, but how often the middle one runs is not. A runtime that re-runs the whole component body on each change re-executes everything in that body, so the distinction between "setup" and "per-update" code has to be made explicit by the author. A runtime with fine-grained tracking runs the body once per instance and afterwards re-evaluates only the expressions whose sources changed, which makes the body itself effectively a creation phase and pushes per-update work into the tracked expressions. A compile-time model splits the body into a create path and an update path during compilation. Write to the strictest reading - assume the body may run again - and the component is correct under all three. ## The misplacements you will actually find in review - A subscription created in per-update code, producing one extra live subscription per update. - Initial state recomputed from an input on every update, silently discarding what the user has changed since. - A request started inline while output is produced, so an abandoned or repeated update fires it again. - An acquisition in creation with no registered release, which survives the instance. - Teardown treated as something that only happens on navigation, so it is never tested. - Per-update code that assumes it ran exactly once since the last user action, and counts or appends accordingly.
- Why is it unsafe to assume the update phase runs exactly once per state change?Because changes are batched, ancestors can force an update with nothing new, some runtimes re-evaluate output whenever any read value changes, and work in progress can be abandoned before it is applied. Per-update code therefore has to be repeatable: anything that counts, appends or fires cannot live there.
- Where does work that must run after the instance's output has been applied belong?Not inline in output production, which may run and be thrown away. It is scheduled through the runtime's post-update mechanism, so it runs after the output actually reached the host, and it registers its own release so that a teardown between scheduling and running is safe.
- What should creation not be used for?Anything that is meant to exist once per application rather than once per instance, such as a shared cache, a global listener or a connection pool. Creation runs again for every instance and for every replacement at the same position, so process-wide setup there is duplicated instead of shared.
saying these in an interview costs you the question
- Puts one-time setup in code that runs every update
- Assumes update code runs once per state change
- Mutates state while producing output
- Acquires in creation without registering a release
- Thinks teardown only happens on navigation