liveBook · Manning

updateState

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

A book-specific component function that merges new state into current component state and updates the corresponding DOM.

updateState is the component method for changing internal state without losing existing fields. It merges the supplied state into the current state, then triggers rendering and DOM patching so the view reflects the change. section 9.1.1 section 9.3.2

The mechanism has three small responsibilities:

  • Merge partial state with the spread expression: this.state = { ...this.state, ...state }. Unmentioned state properties remain available. section 9.3.1
  • Call the private patch routine after updating state. section 9.3.1
  • Have patch render a new virtual DOM, compare it with the previous virtual DOM, and apply the result through patchDOM(). section 9.3.1
  • Reject patching when the component is not mounted; updateState therefore operates on a mounted component. section 9.3.1
Listing 9.4 Update the state and the component’s DOM (component.js)
import { destroyDOM } from './destroy-dom'
import { mountDOM } from './mount-dom'
import { patchDOM } from './patch-dom'

export function defineComponent({ render, state }) {
  class Component {
    #isMounted = false
    #vdom = null
    #hostEl = null

    constructor(props = {}) {
      this.props = props
      this.state = state ? state(props) : {}
    }

    updateState(state) {
      this.state = { ...this.state, ...state }  #1
      this.#patch()  #2
    }

    render() {
      return render()
    }

    mount(hostEl, index = null) {
 // --snip-- //
    }
    unmount() {
 // --snip-- //
    }

    #patch() {
      if (!this.#isMounted) {  #3
        throw new Error('Component is not mounted')
      }

      const vdom = this.render()  #4
      this.#vdom = patchDOM(this.#vdom, vdom, this.#hostEl)  #5
    }
  }

  return Component
}

The implementation listing shows the complete update path: merge state, invoke #patch(), render, and patch the component DOM. section 9.3.1

Incrementing a counter

A counter can call updateState from a button handler: updateState({ count: this.state.count + 1 }). The render function reads this.state.count, so the next virtual DOM contains the incremented label. The render callback must be bound with render.call(this); otherwise this can be undefined and reading count fails. section 9.3.1

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

How deep it goes
Implements shallow state merging and virtual-DOM patching, while stopping short of production-level completeness or optimization.
Examples
Uses a counter button that increments count and an exercise that moves a FlyingButton to random viewport positions.
What it assumes
Assumes basic JavaScript objects and this binding while teaching stateful components, rendering, and DOM patching incrementally.
What you can do after
Build it from scratch by merging partial state, invoking a patch routine, and binding render callbacks to the component instance.
How it connects
Connects component state with render, virtual DOM, DOM patching, lifecycle mounting, event handlers, and props passed to child components.

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.