Skip to content

fix: prevent stale re-renders of #each items during sequence update (#468)#501

Open
dupontbertrand wants to merge 3 commits intometeor:release-3.1.0from
dupontbertrand:fix/each-stale-data-context
Open

fix: prevent stale re-renders of #each items during sequence update (#468)#501
dupontbertrand wants to merge 3 commits intometeor:release-3.1.0from
dupontbertrand:fix/each-stale-data-context

Conversation

@dupontbertrand
Copy link
Copy Markdown

Summary

Fixes #468

When the data source of a parent template changes, Tracker can re-run helpers inside #each item views before ObserveSequence has had a chance to diff and remove stale items. This causes items to briefly render with inconsistent data — e.g., an item's msg shows "foo" while the parent data context already says "bar".

Root cause

During Tracker.flush(), autoruns are re-run in invalidation order. When a parent data context changes:

  1. Helper autoruns inside existing #each item views are invalidated (via bindDataContextBlaze.getData()dataVar.get())
  2. The ObserveSequence autorun is also invalidated (it depends on the sequence function)
  3. The item helper autoruns can re-run BEFORE ObserveSequence diffs and removes stale items
  4. Result: stale item views re-render with old item data but new parent data

Fix

Freeze item views during sequence transitions using 3 hooks:

  • onInvalidate (new callback in ObserveSequence.observe): called immediately when the sequence source is invalidated, BEFORE Tracker.flush() re-runs other autoruns. Marks all current item views with _eachItemPendingUpdate = true.
  • afterDiff (new callback): clears the flag on surviving item views after the diff is applied.
  • doRender guard (in _materializeView): skips re-render if the view or any ancestor has _eachItemPendingUpdate set.

This ensures stale item views never re-render — they are either destroyed by removedAt or updated by changedAt, and the flag is cleared afterward.

Files changed

File Change
packages/observe-sequence/observe_sequence.js Add onInvalidate, beforeDiff, afterDiff callback hooks
packages/blaze/builtins.js Implement hooks in Blaze.Each to freeze/unfreeze item views
packages/blaze/view.js Guard in doRender to skip re-render when pending update

Test plan

  • Tested with 5 scenarios in a dedicated test app:
    1. Different IDs (removedAt + addedAt) — original bug report
    2. Same ID, changed content (changedAt)
    3. Multiple items reduced to one (3 removedAt)
    4. New-style #each item in items
    5. Nested #each (outer + inner)
  • All 5 scenarios produce zero stale renders
  • Full Tinytest suite: 416/416 passed, 0 failures

When the data source of a parent template changes, Tracker can re-run
helpers inside #each item views before ObserveSequence has had a chance
to diff and remove stale items. This causes items to briefly render with
inconsistent data (e.g., item shows "foo" while parent data says "bar").

Fix by freezing item views during sequence transitions:

- observe_sequence.js: add onInvalidate, beforeDiff, and afterDiff
  callbacks so callers can hook into the sequence update lifecycle
- builtins.js: use onInvalidate to mark item views with
  _eachItemPendingUpdate immediately when the sequence is invalidated
  (before Tracker flush), and afterDiff to clear the flag on survivors
- view.js: skip doRender re-runs when the view or an ancestor has
  _eachItemPendingUpdate set

Tested with 5 scenarios: different IDs, same ID with changed content,
multiple items removed, new-style #each (each-in), and nested #each.

Fixes meteor#468
Add two Tinytest cases that verify #each item views don't re-render
with stale data when the parent data context changes:
- Different IDs (removedAt + addedAt) — the original bug report
- New-style #each item in items syntax
@jankapunkt jankapunkt mentioned this pull request Apr 3, 2026
18 tasks
@jankapunkt jankapunkt added this to the 3.1 milestone Apr 8, 2026
@jankapunkt jankapunkt added the ready2review feel free to add your review to this PR label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready2review feel free to add your review to this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants