I started playing with xstate and decided to start with making a fetch machine that will be responsible for every request I make to the server.
I created a simple state machine:
import { createMachine, assign } from "xstate";
interface FetchContext {
readonly results: any | null;
readonly error: null | string;
}
type FetchServices = {
readonly fetchData: {
readonly data: any;
};
}
export const fetchMachine = createMachine(
{
context: {
results: null,
error: null,
},
tsTypes: {} as import("./fetch.typegen").Typegen0,
schema: {
context: {} as FetchContext,
services: {} as FetchServices,
},
id: "fetch",
initial: "idle",
states: {
idle: {
on: {
FETCH: {
target: "pending",
},
},
},
pending: {
invoke: {
src: "fetchData",
onDone: { target: "success", actions: "setResults" },
onError: { target: "failed", actions: "setError" },
},
},
success: {
on: {
FETCH: {
target: "pending",
},
},
},
failed: {
on: {
FETCH: {
target: "pending",
},
},
},
},
},
{
actions: {
setResults: assign((context, event) => {
return {
results: event.data,
error: null,
};
}),
setError: assign((context, event) => {
return {
results: null,
error: event.data as string,
};
}),
},
}
);
The main problem here is that I want this fetchMachine to be responsible for different requests with different return types. As you can see fetched data type in my code is "any" and I want to fix that. If I used the fetchMachine just for one request, I would describe returned object type and the problem would be gone, but in my case I want this fetchMachine to be reused for many different services.
The second problem (not related to services) is that if I remove "as string" from "setError" action's returned propery "error", typescript complains that "event.data" is unknown type and can not be assigned to "string | null" as I described error type in FetchContext interface. Is there a way to properly type errors in this case?
Also, is it a good practice to have a single fetching machine for every "get" request in state machines? I mean, sometimes I used to create a useFetch hook to handle most of the requests, that's why I'm asking.