[XState] Invoke with callback
Invoke not only able to return a promise, but also a callback function with 'sendBack' & 'receive' callbacks
invoke: { // nested state with id reference id: "child", // return a callback function src: (context, event) => (sendBack, receive) => { setTimeout(() => { // send out a event sendBack({ type: "I_AM_DONE", }); }, 5000); // wait for receiving a event receive((event) => { console.log("event", event); if (event.type === "SNED_IT_ALREADY") { sendBack({ type: "I_AM_DONE", }); } }); },
Receive a event:
on: { RESOLVE: "resolved", // cancel the promise CANCEL: "idle", I_AM_DONE: "resolved", SNED_IT_ALREADY: { actions: send( { type: "SNED_IT_ALREADY", }, { to: "child", } ), }, },
--- Full code---
import { createMachine, assign, interpret, send } from "xstate";
const elBox = document.querySelector("#box");
const randomFetch = () => {
return new Promise((res, rej) => {
setTimeout(() => {
if (Math.random() < 0.5) {
rej("Fetch failed!");
} else {
res("Fetch succeeded!");
}
}, 2000);
});
};
const machine = createMachine({
initial: "idle",
states: {
idle: {
on: {
FETCH: "pending",
},
},
pending: {
on: {
RESOLVE: "resolved",
// cancel the promise
CANCEL: "idle",
I_AM_DONE: "resolved",
SNED_IT_ALREADY: {
actions: send(
{
type: "SNED_IT_ALREADY",
},
{
to: "child",
}
),
},
},
invoke: {
// Invoke your promise here.
// The `src` should be a function that returns the source.
/* Promise
src: (context, event) => {
return randomFetch();
},
*/
id: "child",
src: (context, event) => (sendBack, receive) => {
setTimeout(() => {
sendBack({
type: "I_AM_DONE",
});
}, 5000);
receive((event) => {
console.log("event", event);
if (event.type === "SNED_IT_ALREADY") {
sendBack({
type: "I_AM_DONE",
});
}
});
},
onDone: {
target: "resolved",
},
onError: {
target: "rejected",
},
},
},
resolved: {
// Add a transition to fetch again
on: {
FETCH: "pending",
},
},
rejected: {
// After 2s, retry again
after: {
2000: {
target: "pending",
},
},
},
},
});
const service = interpret(machine);
service.onTransition((state) => {
elBox.dataset.state = state.toStrings().join(" ");
console.log(state);
});
service.start();
elBox.addEventListener("click", (event) => {
service.send("FETCH");
});
const cancelBtn = document.querySelector("#cancel");
cancelBtn.addEventListener("click", (event) => {
service.send("CANCEL");
});
const receiveBtn = document.querySelector("#receive");
receiveBtn.addEventListener("click", (event) => {
service.send("SNED_IT_ALREADY");
});

浙公网安备 33010602011771号