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): booleanFilter function called whenever each action starts, and only then. Takes as parameter a simplified action context (more on that later). Returns
trueto accept the action andfalseto skip it.If the action is accepted then
onStart,onResume,onSuspendandonFinishfor that particular action will be called.All actions are accepted by default if no filter function is present.
-
onStart?(ctx: SimpleActionContext): void | ActionTrackingReturnCalled 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): voidCalled 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): voidCalled 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 | ActionTrackingReturnCalled 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: objectSubtree (object and child objects) this middleware will run for. This target "filter" will be run before the custom filter.
-
filter?(ctx: ActionContext): booleanA filter function to decide if an action middleware function should be run or not.
-
middleware(ctx: ActionContext, next: () => any): anyAn 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,undefinedfor sync actions or the first action of a flow.spawnAsyncStepContext?: ActionContext- Spawn async step context, orundefinedfor sync actions.asyncStepType?: ActionContextAsyncStepType- Async step type, orundefinedfor sync actions.data: Record<symbol, any>- Custom data shared by middlewares for this action context. Use symbol keys to avoid collisions between middlewares.