Three ways rows are matched
Whether For is keyed is decided once, when the For is created, by whether key is present.
| Form | Rows are matched by | The callback receives | Use it for |
|---|---|---|---|
<For each={list}> |
the item itself (===, with NaN equal to NaN) |
(item, index): item is the plain value, index is an accessor |
lists of stable objects (store items, objects you reuse) and lists of primitives |
<For each={list} key={(item) => id}> |
key(item) |
(item, index): item is an accessor, index is an accessor |
lists whose objects are replaced by fresh copies (server responses, immutable updates) |
<Index each={list}> |
the position | (item, index): item is an accessor, index is a number |
lists of primitives whose values change in place, inputs bound to positions |
Whether For is keyed is decided once, when the For is created, by whether key is present.
When a list changes, a row survives if its match survives. A surviving row keeps its component state, its DOM node and its effects; a new match creates a row; a vanished match disposes the row (cleanups run once). The new row order moves existing nodes with the minimum number of moves; it never recreates a node that is still present.
Moving nodes and focus#
A node that has to change position is moved with Node.prototype.moveBefore where the browser implements it, which keeps focus, selection, scroll position and iframe state. In browsers without it, the move is a remove and an insert, and a focused control inside the moved row loses focus. Rows that do not need to move are never touched.