Skip to content

fix: release repeat views when the host disconnects#7650

Open
AKnassa wants to merge 1 commit into
microsoft:mainfrom
AKnassa:fix/7144-repeat-unbind-view-teardown
Open

fix: release repeat views when the host disconnects#7650
AKnassa wants to merge 1 commit into
microsoft:mainfrom
AKnassa:fix/7144-repeat-unbind-view-teardown

Conversation

@AKnassa

@AKnassa AKnassa commented Jul 13, 2026

Copy link
Copy Markdown

What this does

Fixes a list (repeat) that comes back wrong after its component is taken out of the page and put back — which is what happens on a route change, a tab switch, or any time the DOM is moved.

Why

When a component was removed from the page, repeat let go of its data but kept its rendered rows. So when the component came back, it reused those stale rows instead of rebuilding them.

Two things went wrong as a result:

  • If the list data changed while the component was away, you got errors from bindings pointing at data that no longer existed.
  • Every row in the list fired its "disconnected" lifecycle callback twice, and both times before the parent's "connected" callback — the kind of ordering bug that is nearly impossible to attribute to its cause.

What changed

01-before-bug 02-after-fixed
  • When a list is genuinely being torn down, its rows' DOM is now parked and restored on the way back, rather than left dangling. Element instances and their state survive a DOM move.
  • A list that is simply being handed new data (the recycling path used by nested lists) is untouched, so the fast path stays fast.
  • Notifications that arrive while a list is detached are now ignored, matching the guards that already exist on the other view behaviors.

How to see it

Run the fast-element test suite. templating/repeat-reconnect.pw.spec.ts is new: it removes a component containing a list, changes the data, puts it back, and asserts the rows are rebuilt rather than resurrected. Those tests fail on main.

Performance was measured, because this is a hot path. Every steady-state scenario — create, reuse, splice, and the nested-recycle case that a naive version of this fix would have wrecked — comes out at parity with main. The added cost lands only on disconnect and reconnect (roughly 0.2 ms for a 500-row list per full cycle), which is not a per-frame path, and it is the price of actually taking the DOM out while detached. In the scenario this issue describes, the fixed version is likely faster, since main currently resurrects rows and then tears them down again.

Note for reviewers

RepeatBehavior.unbind() now takes the controller, and views carry an internal isUnbinding flag. That flag is what distinguishes "this controller is going away" from "this view is being recycled with new data" — without it, teardown would rebuild every nested list's DOM on every recycled row, which would be a real regression.

Fixes #7144

A repeat kept its views alive on unbind, so reconnecting the host reused the
stale views instead of rebuilding them. Route swaps, tab switches and DOM moves
produced binding errors against a nulled source, and every repeated element
fired disconnectedCallback twice.

The views' DOM is now parked when the controller is genuinely going away, and
restored on rebind, so element instances survive a DOM move. A recycled view
rebinding to new data is unaffected, keeping the nested-repeat path at parity.
Stale notifications arriving while unbound are ignored, matching the guards
already present on the other view behaviors.

Fixes microsoft#7144
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@AKnassa AKnassa marked this pull request as ready for review July 14, 2026 02:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

repeat directive may cause binding error on re-rendering view

1 participant