onActionMiddleware
This middleware observes actions in a given tree. It invokes listeners only for top-level actions, not for nested child actions or intermediate flow steps. Life-cycle hooks such as onAttachedToRootStore and its returned disposer are also excluded.
Its main use is to keep track of top-level actions that can be later replicated via applyAction somewhere else (another machine, etc.).
There are two kinds of possible listeners, onStart and onFinish listeners.
onStartlisteners are called before the action executes and allow cancellation by returning a new result (either a return or a throw).onFinishlisteners are called after the action executes, have access to the action's actual return value and allow overriding by returning a new return value (which might be a return or a throw).
The ActionCall passed to a listener is not directly serializable. To store or send it, encode it with a serializer (e.g. defaultSerializer.encodeCall(root, actionCall)), and run it on the other side with decodeCall and applyCall / applyCallAsync, as shown in the Client/Server Example. Encode it in onStart, before the action runs, so its arguments are encoded against the tree the receiver has.
It will return a disposer, which only needs to be called if you plan to early dispose of the middleware.
const disposer = onActionMiddleware(myTodoList, {
onStart(actionCall, actionContext) {
// we could encode the action call as JSON and do something with it
const encodedCall = defaultSerializer.encodeCall(getRoot(myTodoList), actionCall)
// optionally cancel the action by throwing something
return {
result: ActionTrackingResult.Throw,
value: new Error("whatever"),
}
// or by returning a different value
// return {
// result: ActionTrackingResult.Return,
// value: 42,
// }
// or do nothing / return `undefined` to continue it
},
onFinish(actionCall, actionContext, ret) {
if (ret.result === ActionTrackingResult.Return) {
// the action succeeded and `ret.value` has the return value
} else if (ret.result === ActionTrackingResult.Throw) {
// the action threw and `ret.value` has the thrown value
}
// as in above, we can either return an object with what to return / throw
// or do nothing / return `undefined` to continue the action
},
})