Skip to main content

customMiddlewares

Overview

Use onActionMiddleware when you only need top-level, replayable action calls. For custom interception and instrumentation, mobx-keystone exposes two more APIs: the higher-level actionTrackingMiddleware and the rarely needed low-level addActionMiddleware.

actionTrackingMiddleware

actionTrackingMiddleware(subtreeRoot, hooks) creates a middleware that treats every synchronous action or complete async flow as one logical action.

The first argument is the root of the subtree to observe. The second is an ActionTrackingMiddleware hooks object. The function returns a disposer.

The ActionTrackingMiddleware object has the following structure:

  • filter?(ctx: SimpleActionContext): boolean

    Filter function called whenever each action starts, and only then. Takes as parameter a simplified action context (more on that later). Returns true to accept the action and false to skip it.

    If the action is accepted then onStart, onResume, onSuspend and onFinish for that particular action will be called.

    All actions are accepted by default if no filter function is present.

  • onStart?(ctx: SimpleActionContext): void | ActionTrackingReturn

    Called when an action starts. Takes as parameter a simplified action context (more on that later). Can optionally return a result that will cancel the original action and finish it with the returned value / error to be thrown. In either case, resume / suspend / finish will still be called normally.

  • onResume?(ctx: SimpleActionContext): void

    Called when an action resumes a synchronous segment of execution. It runs once for synchronous actions and multiple times for flows. Takes as parameter a simplified action context (more on that later).

  • onSuspend?(ctx: SimpleActionContext): void

    Called when an action suspends after a synchronous segment of execution. This does not necessarily mean the action has finished. It runs once for synchronous actions and multiple times for flows. Takes as parameter a simplified action context (more on that later).

  • onFinish?(ctx: SimpleActionContext, ret: ActionTrackingReturn): void | ActionTrackingReturn

    Called when an action finishes, either by returning normally or by throwing an error.

    Takes as parameters:

    • ctx - Simplified action context (more on that later).
    • ret: { result: ActionTrackingResult; value: any } - Whether the action finished normally or due to a thrown error, and the returned / thrown value.

    Can optionally return a new return / error value to override the result of the action.

SimpleActionContext

Simplified version of action context, which includes the following readonly data:

  • actionName: string - Action name.
  • type: ActionContextActionType - Action type, sync or async.
  • target: AnyModel - Action target model instance.
  • args: ReadonlyArray<any> - Array of action arguments.
  • parentContext?: SimpleActionContext - Parent action context, if any.
  • rootContext: SimpleActionContext - Root action context, or itself if the root.
  • data: Record<symbol, any> - Custom data shared by middlewares for this action context. Use symbol keys to avoid collisions between middlewares.

It is simplified in the sense that it treats all synchronous steps of an asynchronous action as part of the same context, which removes most of the differences between sync actions and flows.

addActionMiddleware

addActionMiddleware attaches a low-level middleware to a subtree. Prefer actionTrackingMiddleware unless you need to work with individual async flow steps or control the next() chain directly.

It takes a single parameter, an ActionMiddleware object and returns a disposer function.

The ActionMiddleware object has the following structure:

  • subtreeRoot: object

    Subtree (object and child objects) this middleware will run for. This target "filter" will be run before the custom filter.

  • filter?(ctx: ActionContext): boolean

    A filter function to decide if an action middleware function should be run or not.

  • middleware(ctx: ActionContext, next: () => any): any

    An action middleware function. Remember to return next() if you want to continue the action or throw if you want to cancel it.

ActionContext

Low-level action context, which includes the following readonly data:

  • actionName: string - Action name.
  • type: ActionContextActionType - Action type, sync or async.
  • target: object - Action target object.
  • args: ReadonlyArray<any> - Array of action arguments.
  • parentContext?: ActionContext - Parent action context, if any.
  • rootContext: ActionContext - Root action context, or itself if the root.
  • previousAsyncStepContext?: ActionContext - Previous async step context, undefined for sync actions or the first action of a flow.
  • spawnAsyncStepContext?: ActionContext - Spawn async step context, or undefined for sync actions.
  • asyncStepType?: ActionContextAsyncStepType - Async step type, or undefined for sync actions.
  • data: Record<symbol, any> - Custom data shared by middlewares for this action context. Use symbol keys to avoid collisions between middlewares.