Skip to content

Implement Keyed Reconciliation for {@for...trackBy} Loops #1

Description

@vcrobe

Summary

The {@for} loop syntax mandates a trackBy clause, which is a key part of our framework's "correct by default" philosophy. This syntax is parsed by the "Go Inspector" compiler, but the corresponding DOM reconciliation logic in the runtime does not yet use the provided key.

This issue tracks the work to implement a keyed diffing algorithm in our VDOM runtime. This is critical for enabling high-performance, predictable list rendering.

Problem

Without keyed reconciliation, the runtime can only diff lists of children by their index. This leads to two major problems:

  1. Poor Performance: When a list is re-sorted, or an item is added/removed from the beginning, an index-based diff will incorrectly assume every single item in the list has changed. This causes a cascade of unnecessary DOM updates (or worse, full teardown and rebuild) instead of a simple, surgical change.
  2. Incorrect Behavior: State held in child components (like IsChecked in a checkbox) can be lost or "smeared" across the wrong components during a re-render, as the framework misidentifies which component is which.

Proposed Solution

We must upgrade the runtime's patch/diffing algorithm to perform a keyed reconciliation when diffing an element's children.

This algorithm, inspired by patterns in Blazor, React, and Angular, should generally follow these steps when comparing the old list of child VNodes to the new list:

  1. Create a map of the old VNodes (or their corresponding DOM elements) indexed by their key.
  2. Iterate through the new list of VNodes.
  3. For each newVNode, check its key against the "old key map."
    • Key Found (Update/Move): If the key exists, we know this is the same element. We patch this existing element with the new VNode's properties and move it to the correct new index in the DOM. We then remove it from the "old key map."
    • Key Not Found (Add): This is a new item. Create a new DOM element and insert it at the current index.
  4. Cleanup (Remove): After iterating through the new list, any VNodes remaining in the "old key map" no longer exist in the new list. These elements must be unmounted and removed from the DOM.

Acceptance Criteria

  • The VDOM patch/diffing algorithm is updated to use the key provided by VNodes.
  • Addition: Adding a single item to the beginning of a list only creates one new DOM element and does not affect the other elements.
  • Removal: Removing a single item from the middle of a list only removes that one DOM element.
  • Re-ordering: Re-sorting a list (e.g., reversing it) results in DOM moves (insertBefore), not the destruction and re-creation of all list elements.
  • Key-only Swap: Swapping two non-adjacent items in a list correctly moves the two corresponding DOM elements without affecting siblings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions