liveBook · Manning

Move method

As explained in Build a Frontend Web Framework (From Scratch)

A move operation represents relocating an existing array item to a different position while preserving its original index.

When virtual-node children change order, an array diff can describe the change as operations for patching the DOM. A move relocates an existing item; unlike an add, it does not create one. It is one of four operation types: add, remove, move, and noop. section 7.6 section 7.6.1

A move has the shape `{ op: 'move', item, originalIndex, from, index }`. `from` is the item's position when the operation runs, `index` is its destination, and `originalIndex` is its position before diffing began. Keep both positions: earlier removals, additions, or moves may have changed the current index. section 7.6.1 section 7.6

A removal changes the move's starting position

To change `[A, B, C]` into `[C, B, D]`, remove `A` first. `C` started at index 2 but is now at index 1, so its move is `{ op: 'move', item: 'C', originalIndex: 2, from: 1, index: 0 }`. `B` needs no explicit move; record a noop for it, then add `D`. section 7.6.1 section 7.6

To implement the move case in `arraysDiffSequence()`:

  • Work on a copy of the old array, alongside an array that tracks each item's original index. section 7.6.4
  • At the current destination index, handle removals, noops, and additions first. If the desired item instead appears later in the working array, move it. section 7.6.2 section 7.6.4
  • In `moveItem(item, toIndex)`, find the current position, emit the move operation, and splice both the item and its saved original index to the destination. section 7.6.4
Listing 7.15 Detecting whether an operation is addition (utils/arrays.js)
class ArrayWithOriginalIndices {
 // --snip-- //

  moveItem(item, toIndex) {
    const fromIndex = this.findIndexFrom(item, toIndex)     #1

    const operation = {                                 #2
      op: ARRAY_DIFF_OP.MOVE,
      originalIndex: this.originalIndexAt(fromIndex),      #3
      from: fromIndex,
      index: toIndex,
      item: this.#array[fromIndex],
    }

    const [_item] = this.#array.splice(fromIndex, 1)     #4
    this.#array.splice(toIndex, 0, _item)                #5

    const [originalIndex] =
     this.#originalIndices.splice(fromIndex, 1)             #6
    this.#originalIndices.splice(toIndex, 0, originalIndex)    #7

    return operation       #8
  }
}

The `moveItem()` listing shows why the item array and original-index array must move together. section 7.6.4

Not every changed position calls for a move. An item can fall into place when another item is removed or moved; a noop records its initial and final indices so its children can still be compared during recursive DOM patching. section 7.6.1

How Build a Frontend Web Framework (From Scratch) covers it

How deep it goes
Defines the operation's fields, works through index changes, and implements moving items while preserving original indices.
Examples
Uses array transformations, including `[A, B, C]` to `[C, B, D]`, and a step-by-step example with duplicate items.
What it assumes
Assumes familiarity with JavaScript arrays and functions while explicitly introducing original-index tracking and an item-comparison function.
What you can do after
Build it from scratch in JavaScript by emitting move operations and updating parallel item and original-index arrays.
How it connects
Connects array diffing and virtual DOM reconciliation to add, remove, and noop operations.

Also explained in

Compare how 2 books explain move method →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build a Frontend Web Framework (From Scratch). The section links point to the parts of the book it draws on.