liveBook · Manning

Lifecycle method

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

A lifecycle hook is a component callback associated with a defined moment in the component's lifecycle.

A lifecycle method runs code at a defined point in a component’s life. A component is created, mounted into the DOM, possibly updated, and eventually unmounted. Hooks let component developers attach their own behavior to those moments instead of waiting for a user event. section 13.0 section 13.1

Two useful hooks are:

  • onMounted(): run code after the component is mounted. For example, start fetching data while the component displays a loading indicator. section 13.0 section 13.1
  • onUnmounted(): run code after the component is removed from the DOM. section 13.1

To add these hooks, accept onMounted and onUnmounted in defineComponent(), defaulting each to an empty function so callers can omit them. Give the Component class methods that invoke the supplied functions with the component instance as this; that lets a hook access its state and methods. Return Promise.resolve(...) from each method so callers can handle synchronous and asynchronous hooks consistently. section 13.2 section 13.2.2 section 13.2.3

Timing needs care. Awaiting a data-fetching onMounted() hook inside mountDOM() would hold up the components that follow it. Calling the hook without awaiting it avoids that immediate wait but leaves its promise unmanaged. Instead, enqueue the mounted hook after creating the component node, and enqueue the unmounted hook after removing the component. The scheduler runs these jobs in order after mounting or unmounting finishes. section 13.3 section 13.3.1 section 13.3.6

Listing 13.5 Scheduling the onMounted() method of a component (mount-dom.js)
import { setAttributes } from './attributes'
import { addEventListeners } from './events'
import { DOM_TYPES } from './h'
import { enqueueJob } from './scheduler'                 #1
import { extractPropsAndEvents } from './utils/props'

export function mountDOM(vdom, parentEl, index, hostComponent = null) {
  switch (vdom.type) {
 // --snip-- //

    case DOM_TYPES.COMPONENT: {
      createComponentNode(vdom, parentEl, index, hostComponent)
      enqueueJob(() => vdom.component.onMounted())      #2
      break
    }

    default: {
      throw new Error(`Can't mount DOM of type: ${vdom.type}`)
    }
  }
}

// --snip-- //

The mountDOM() listing shows the small but important distinction: create the component node first, then enqueue its onMounted() method rather than executing it during mounting. section 13.3.6

Check the execution order

Make a component whose onMounted() logs a name prop. Mount several instances, then place browser log breakpoints where mountDOM() finishes and where hooks are enqueued and executed. Check that mounting completes before the queued hooks run, and that the hooks run in enqueue order. section 13.3.6

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

How deep it goes
Builds optional mounted and unmounted hooks, binds their component context, and schedules execution; leaves other lifecycle stages without implemented hooks.
Examples
Uses a mounted data fetch and a browser-breakpoint exercise with named components to expose hook timing.
What it assumes
Assumes component classes, render methods, and DOM mounting while explaining hook timing and asynchronous execution.
What you can do after
Build it from scratch by defining component hooks and enqueueing them at the appropriate DOM lifecycle points.
How it connects
Connects component state and methods, DOM mounting, asynchronous promises, the scheduler, and the microtask queue.

Also explained in

Compare how 3 books explain lifecycle 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.