liveBook · Manning

React key

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

A key prop is a virtual-node property that uniquely identifies an item or component so its corresponding interface node can be tracked across updates.

When a list changes, position alone cannot tell a reconciliation algorithm which item survived. This matters especially for stateful components: a newly rendered virtual node does not contain the existing component instance or its state. A key gives each item an identity the algorithm can compare across updates. section 12.0 section 12.1

Removing a counter

Imagine three counters keyed `counter-0`, `counter-1`, and `counter-2`. Remove the middle one. The remaining keys tell reconciliation that `counter-2` survived and changed position; its current count cannot be inferred from the newly created virtual node. section 12.0 section 12.1

A small virtual-DOM implementation gives the key three responsibilities:

  • Compare component nodes by both component definition (`tag`) and `props.key`. Two nodes of the same component type are not necessarily the same list item. section 12.1.1 section 12.1.2
  • Compare element nodes by both tag and key, so reconciliation has an identity to use when elements move. section 12.2
  • Remove `key` before passing props to a component or setting attributes on a DOM element. It is for reconciliation, not an ordinary component prop or DOM attribute. section 12.1.2 section 12.2
Listing 12.2 Using the key attribute to compare component nodes (nodes-equal.js)
export function areNodesEqual(nodeOne, nodeTwo) {
  if (nodeOne.type !== nodeTwo.type) {
    return false
  }

  if (nodeOne.type === DOM_TYPES.ELEMENT) {
    const { tag: tagOne } = nodeOne
    const { tag: tagTwo } = nodeTwo

    return tagOne === tagTwo
  }

  if (nodeOne.type === DOM_TYPES.COMPONENT) {
    const {
      tag: componentOne,
      props: { key: keyOne },  #1
    } = nodeOne
    const {
      tag: componentTwo,
      props: { key: keyTwo },  #2
    } = nodeTwo

    return componentOne === componentTwo && keyOne === keyTwo  #3
  }

  return true
}

The component equality check is the core implementation step: it requires both matching component definitions and matching keys. section 12.1.2

Choose a key that stays with the same item for its whole lifetime and is unique among items in the same list. Different lists may reuse a key. Component lists need keys to distinguish stateful instances; element lists can render without them, but keys can avoid unnecessary reconciliation work. section 12.3.1 section 12.3.2 section 12.6

Two tempting mistakes

Do not key changing lists by array index: removing the middle counter changes the last counter’s index, making it appear to be a different item. Do not give two counters the same key: after one is removed, reconciliation cannot tell which survived. section 12.3.1 section 12.3.2

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

How deep it goes
Implements component and element equality checks using tags and keys, then removes keys before passing props or setting DOM attributes.
Examples
Uses counter removal, swapped list elements, index keys, and duplicate keys to expose correct and ambiguous identity matches.
What it assumes
Assumes JavaScript objects and props; develops component-node comparison from node types, component definitions, and keys.
What you can do after
Build it from scratch by comparing keyed virtual nodes and withholding keys from rendered props and attributes.
How it connects
Connects virtual DOM reconciliation, component state, component props, DOM attributes, and list reordering.

Also explained in

Compare how 3 books explain React key →

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.