-
-
Couldn't load subscription status.
- Fork 1.2k
Description
Hi
I mentioned this in the discord channel and @phryneas was kind enough to talk me through how awaited dispatched rtkquery requests should be handled. He believed that what I was seeing shouldn't happen and asked me to create a code sandbox.
I've now done that and its available here - https://codesandbox.io/s/peaceful-tereshkova-rvumb
In the demo I'm using MSW to mock out all the data responses to clarify that it wasn't something funky with the actual API I consume.
I'm using xState to model loading and deleting data from an API:
The machine list.machine.ts starts off making a list request, then you can send 'DELETE_ITEM' event to ask the machine to transition to the delete state,at which it invokes the 'deleteListData' service, containing the rtkQuery api.endpoint call to delete a list item. At this point:
- In the console's network tab the mock service worker has returned a new response with that item deleted
- However, at the same time in the console you will see the awaited dispatch function return a status pending response, containing the stale data.
- I'm guessing some time after this the store's data is finally updated with the request data, because if you delete the same item again the new list request still reports as pending but now its stale data contains the results from the previous request.
This has me stumped! So any help greatly appreciated
If I update the machine to delay between transitioning between the delete and list states then things work as expected:
import { createModel } from "xstate/lib/model";
import { ModelContextFrom, ModelEventsFrom } from "xstate/lib/model.types";
import {
Destination,
ListDestinationsResponse
} from "../service/destinations-api.generated";
export const listModel = createModel(
{
data: [] as Destination[]
},
{
events: {
DELETE_ITEM: (id: string) => ({ id })
}
}
);
export const listMachine = listModel.createMachine({
id: "list",
initial: "loading",
states: {
loading: {
invoke: {
src: "fetchListData",
onDone: {
actions: assign({
data: (
context,
event: DoneInvokeEvent<ListDestinationsResponse>
) => {
console.log("assign ", event.data.destinations);
return event.data.destinations ?? [];
}
}),
target: "idle"
},
onError: {
target: "error"
}
}
},
error: {},
idle: {
on: {
DELETE_ITEM: {
target: "delete"
}
}
},
pause: {
after: {
// after 0.1 second, transition to loading
100: { target: "loading" }
}
},
delete: {
invoke: {
src: "deleteListData",
onDone: {
target: "pause"
}
}
}
}
});
export type DestinationsListContext = ModelContextFrom<typeof listModel>;
export type DestinationsListEvent = ModelEventsFrom<typeof listModel>;
export type DestinationsListService = ActorRefFrom<typeof listMachine>;