skip to content

Why must an entering component's first output carry a start state that changes to the end state only on a later frame?

level: middleimportance: should knowfreq 38%

answer

  1. the host animates a change
  2. two observed values, not one
  3. attach in the start state first
  4. flip to the end state a frame later
  5. declared keyframes skip the second step

basics

~20 s

A transition interpolates between two observed values. An element attached already in its end state gives the host nothing to animate from, so the first output commits the start state and a later frame moves it to the end state.

solid answer

~50 s

Because the host animates a *change*, not a destination. The element has to exist with the start value applied, the host has to settle on that value, and only then does a change to the end value give it two values to interpolate between. If the first output already carries the end value, the element simply appears finished. So the entering phase is two steps the author can delay: the first output goes in with an entering state, and after the runtime has applied it - a frame later, or after forcing the host to settle the current value - the state flips to its final one and the transition runs. A self-declaring keyframe animation is the exception, because it names its own start value, so attaching the element is enough. Interruption matters here too: an instance that leaves while entering should reverse rather than restart.

go deeper

for a junior

Remember that an element attached already in its final appearance does not animate. Something has to change after it is on screen for a transition to have two values to move between.

for a middle

Explain the two committed states, why the change has to land after the first output reached the host, and why a self-declaring keyframe animation escapes the second step.

for a senior

Handle the messy parts: suppressing entrances on the initial tree, reversing an interrupted entrance into an exit, and removing the transitional state when no completion signal arrives.

for a principal

Decide whether entrance choreography belongs inside shared components or in the screens that compose them, since it needs a post-commit hook and an identity contract that teams usually get wrong once.

An entering instance has a timing problem that a static one does not: it wants to be animated from a value it never had. The lifecycle answer is to split its arrival into two committed states. ## Why one frame is not enough A transition is defined by a change: the host notices that a property it can interpolate has a different value than the one it last settled on, and it animates between them. That requires the host to have settled the first value. If an element is attached and the end value is applied in the same pass, the host has a single value, never observes a change, and there is nothing to interpolate - the element appears fully formed. So an entering instance needs two committed states in sequence: 1. Its **first output** is produced with the start state - transparent, offset, collapsed, whatever "not yet arrived" means for this component. 2. The runtime applies that output, so the element now exists in the host carrying the start state. 3. The host is made to settle that state, either by waiting for the next animation frame or by reading a value that forces the host to resolve current style now. 4. The state is changed to the end state, and the host observes a change it can animate. 5. When the animation reports finished, the transitional state is removed so the element is left in its ordinary resting form. Steps 3 and 4 are the two the author can delay. Everything else is the normal first-output path. ## The exception: an animation that declares its own start Not every mechanism needs the two-step dance. A declarative keyframe animation carries its start value inside its own definition, so attaching an element with that animation applied is enough to start it: the host does not need a previous value to compare against. | | interpolate between two values | a self-declaring keyframe animation | |---|---|---| | needs a previously settled value | yes | no | | needs a second committed state | yes | no | | start value lives in | the first output's state | the animation's own declaration | | interruption behaviour | reverses naturally from the current value | restarts or jumps unless explicitly handled | | suits | states that also change later, such as open and closed | one-shot arrivals | ## What the runtime has to offer the author - A hook that runs **after** the first output has been applied to the host, not while it is being produced - before that moment there is no element to animate. - A stable place to keep the entering state, so it can be removed once the animation finishes. - Identity, so an item that leaves and re-enters is matched against the instance that is already animating rather than duplicated. - A completion signal, and therefore the same obligation as an exit animation: if the signal never arrives, the transitional state is never removed and the element is left mid-entrance. ## Failure modes - **Nothing animates.** The end state was in the first output; the element appears complete. This is the default outcome of writing an entrance naively. - **Everything animates at once on first paint.** Every instance in the initial tree is an entering instance, so an unconditional entrance rule fires for the entire screen. Entrances that are meant for later insertions have to distinguish the first output of the whole tree from later ones. - **The transitional state sticks.** No finish signal arrives - the animation was cancelled, had zero duration, or the environment suppressed it - and the element keeps the entering state, often invisible. - **A jump on interruption.** An entering instance that is removed mid-entrance and treated as a fresh exit starts its exit from the end state rather than from where it actually is. - **Layout thrash.** Forcing the host to settle style for every item in a long list, one at a time, is a per-item synchronous cost; whether that is affordable is a host-level performance question, not a lifecycle one. ## Where the models differ The lifecycle is the same everywhere; the seam differs. A runtime that re-runs the component body needs the entering state to be derivable from state that changes between the two commits. A fine-grained runtime can flip a single tracked value and have only that one binding update, which makes the second step very cheap. A compile-time runtime may generate the two-step sequence for a declared transition so the author never writes it. In all three the author's real question is the same: is there a supported moment after my first output reached the host and before the next frame is painted?

  • Why do entrance animations sometimes play for a whole screen on its first paint?
    Because every instance in the initial tree is an entering instance, so an unconditional entrance rule applies to all of them. If the effect is only wanted for later insertions, the code has to distinguish the first output of the whole tree from subsequent arrivals and suppress the entrance for that first pass.
  • What should happen when an entering instance is removed before its entrance finishes?
    It should reverse from its current visual state and be handed straight to the leaving path, not restarted from the end state. The pending entrance completion must also be cancelled, so that its cleanup does not strip the transitional state in the middle of the exit.
  • Why can the state flip not simply be done at the end of producing the first output?
    Because at that point the element does not exist in the host yet - the output is still a description. The host can only observe a change between two values it has settled, so the flip has to happen after the runtime applied the first output, which is why the author needs a post-commit hook rather than more code in the body.

saying these in an interview costs you the question

  • Thinks applying the final value at insertion animates it
  • Assumes the host observes every value written within one frame
  • Lets entrance animations run for the whole initial tree
  • Leaves the entering state applied when no finish signal arrives
  • Believes a declared keyframe animation also needs a second frame