Feature Request
With the release of xstate 4.7 we now have a new function called as escalate() which basically is used to send an action of type error back to the parent.
This is very useful when we invoke a machine and if that machine leads to onError, we needed a way to inform its parent about the same.
A discussion around this has already happened here
https://github.com/davidkpiano/xstate/issues/696
The resolution provided was this
https://xstate.js.org/docs/guides/actions.html#escalate-action
Now with this, the problem is if let's say a parent machine invokes another machine and that child machine invokes a promise.
When this promise is rejected it lands into the onError handler on the child machine.
With escalate I can inform the parent machine about this error with a custom error object, but I have no way to send the exact error event that occurerd.
For example currently we can do
escalate({ message: "some error occurred" });
What will be more ideal here is if we could do something like this
escalate((context, event) => ({
event,
message: 'some error occured'
... this could be anything the user wants to send back to the parent
}));
escalate should accept a function also which will have context and event passed to it.
Required! If you would like to see a feature or enhancement make its way to xstate, please describe:
escalate((context, event) => ({
event,
message: 'some error occured',
... this could be anything the user wants to send back to the parent
}));
So it can allow an object, a string or a function.
You can use CodePen or CodeSandbox template to create a reproduction/POC.
Not sure if this is the right approach to solve this but I have certain implementation in mind.
/**
* Escalates an error by sending it as an event to this machine's parent.
*
* @param escalatedError The error data to send or error fn which will return the error data to send
* @param options Options to pass into the send action creator.
*/
export function escalate<TContext, TEvent extends EventObject>(
escalatedError: Mapper<TContext, TEvent> | object | any,
options?: SendActionOptions<TContext, TEvent>
): SendAction<TContext, TEvent> {
return sendParent<TContext, TEvent>(
{
type: actionTypes.error,
data: escalatedError
},
{
...options,
to: SpecialTargets.Parent
}
);
}
Then inside actions.ts we can have a check like this
if (resolvedEvent.name === actionTypes.error) {
isFunction(resolvedEvent.data.data) {
resolvedEvent.data.data = resolvedEvent.data.data(ctx, _event.data);
}
}
As I am no expert in this, it would be great if someone could help me out here.
@davidkpiano any suggestions around this approach or any other way that I should approach this.
I would be happy to send a PR.
It is weird that this was not included in the original design of escalate...
Here's a workaround for anyone needing this functionality now (like me):
import { actionTypes } from "xstate/lib/actions";
// ...
entry: sendParent((context, event) => ({
type: actionTypes.error,
data: {
// Any properties for data
},
})),
Most helpful comment
It is weird that this was not included in the original design of
escalate...Here's a workaround for anyone needing this functionality now (like me):