liveBook · Manning

Dispatcher

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

A dispatcher is an entity that maps commands to handler functions and executes those handlers when the commands are dispatched.

A dispatcher connects command names to the functions that handle them. A component can request an action without choosing a reducer itself: it dispatches a command, and the dispatcher calls the registered handlers. This makes the dispatcher the central routing piece of a small state manager. section 5.1.2 section 5.1.3

Build the mechanism around three operations:

  • subscribe(commandName, handler) stores a handler under a command name and returns a function that unregisters it. Registering the same handler twice for one command does not add it twice. section 5.1.3
  • dispatch(commandName, payload) calls each registered handler with the payload. If none are registered, it warns in the console. section 5.1.3
  • afterEveryCommand(handler) registers a function to run after a command is handled, such as a function that renders the application again. It also returns an unregister function. section 5.1.3 section 5.2.3

The handlers are consumers: each takes the command’s payload and returns no value. A handler can wrap a reducer, which instead takes the current state and payload and returns new state. For example, a remove-todo handler receives an item index and assigns the result of removeTodo(state, index) back to state. section 5.1.3 section 5.1.2

Listing 5.4 Complete Dispatcher implementation (dispatcher.js)
export class Dispatcher {
  #subs = new Map()
  #afterHandlers = []

  subscribe(commandName, handler) {
    if (!this.#subs.has(commandName)) {
      this.#subs.set(commandName, [])
    }

    const handlers = this.#subs.get(commandName)
    if (handlers.includes(handler)) {
      return () => {}
    }

    handlers.push(handler)

    return () => {
      const idx = handlers.indexOf(handler)
      handlers.splice(idx, 1)
    }
  }

  afterEveryCommand(handler) {
    this.#afterHandlers.push(handler)

    return () => {
      const idx = this.#afterHandlers.indexOf(handler)
      this.#afterHandlers.splice(idx, 1)
    }
  }

  dispatch(commandName, payload) {
    if (this.#subs.has(commandName)) {
      this.#subs.get(commandName).forEach((handler) => handler(payload))
    } else {
      console.warn(`No handlers for command: ${commandName}`)
    }

    this.#afterHandlers.forEach((handler) => handler())
  }
}

The complete Dispatcher class shows how a Map of command subscriptions, an array of after-command handlers, and returned unregister functions fit together. section 5.1.4

From a button click to an updated to-do list

A click handler dispatches 'remove-todo' with the item index. The state manager subscribes a handler that passes its payload to the removeTodo reducer and saves the returned state. An after-command handler then renders the application again. Components can use the shorter emit() function instead of calling dispatcher.dispatch() directly. section 5.2.3 section 5.2.4

To check the dispatcher on its own, register a 'greet' handler and an after-command handler. Dispatching 'greet' with 'John' should log “Hello, John!” followed by “Done greeting!” section 5.1.4

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

How deep it goes
Builds a JavaScript class step by step, including registration, unregistration, dispatch, and after-command callbacks; keeps the state manager’s rendering tradeoff simple.
Examples
Uses a remove-todo button and reducer, plus a console exercise that dispatches a greeting command.
What it assumes
Introduces consumer functions and handler registration while relying on JavaScript functions, classes, arrays, and a Map.
What you can do after
Build it from scratch as a Dispatcher class, then use it to connect component commands to reducers and after-command rendering.
How it connects
Connects browser events and components to commands, consumer functions, reducers, state management, and rendering.

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.