Skip to content

Instantly share code, notes, and snippets.

@cellog
Last active April 13, 2020 01:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cellog/cfce7dd6d7e8fdb586881162f8099d35 to your computer and use it in GitHub Desktop.
Save cellog/cfce7dd6d7e8fdb586881162f8099d35 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
const resultsMachine = Machine({
id: "data object paging",
initial: "idle",
context: {
baseUrl: "",
postBody: undefined,
totalRecords: 0,
pageCache: [],
loadingPage: 0,
activePage: 0,
errorMessage: "",
},
states: {
idle: {
on: {
SEARCH: [
{
// if the search has not changed, abort retrieving the same data
target: "",
cond: "isFilterUnchanged",
},
{
// retrieve the next page
target: "loading",
actions: [
// save the query information
assign({
baseUrl: (_, { url }) => url,
postBody: (_, { body }) => body,
pageCache: (
{ pageCache, baseUrl, postBody },
{ url, body }
) => {
if (
baseUrl !== url ||
JSON.stringify(postBody) !== JSON.stringify(body)
) {
// clear the cache if the request URL has changed
return [];
}
return pageCache;
},
}),
// then update the URL (defined below in "actions")
"setQueryString",
],
},
],
SET_ACTIVE_PAGE: [
{
// if the active page is in the cache, no need to re-load it
target: "",
// defined below in "guards"
cond: "isPageCached",
actions: assign({
activePage: (_, { page }) => page,
}),
},
{
// active page is not in the cache, so load it
target: "loading",
actions: assign({
activePage: (_, { page }) => page,
}),
},
],
},
},
loading: {
// on entry, trigger the load
invoke: {
id: "loadPage",
// defined below in "services"
src: "loadPage",
onDone: {
// data loaded successfully
target: "idle",
actions: [
assign({
pageCache: ({ pageCache, loadingPage }, { data }) => {
const pageData = [...pageCache];
pageData[loadingPage] = isAnyObjectOrTemplate(data)
? [data]
: data;
return pageData;
},
totalRecords: ({ pageCache, nextCursor }, { data }) => {
if (true) {
return 1;
}
if (isCursorPagedResult(data) && data.next) {
// we have loaded at least 1 page successfully
if (data.next) {
// ensure we can load at least 1 more
return PER_PAGE * (pageCache.length + 1);
} else {
// return the precise size
return PER_PAGE * pageCache.length + data.contents.length;
}
} else {
return 0;
}
},
nextCursor: (_, { data }) =>
isCursorPagedResult(data) ? data.next : "",
loadingPage: ({ loadingPage }) => loadingPage + 1,
}),
sendParent("PAGE_LOADED"),
],
},
onError: {
target: "error",
actions: assign({
errorMessage: (_, { data }) => data.message,
}),
},
},
},
error: {
entry: sendParent("LOAD_ERROR"),
on: {
CLEAR_ERROR: "idle",
},
},
},
}, {
services: {
loadPage: ({ baseUrl, postBody }) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve({ result: 5 });
}
reject(new Error("error"));
}, 1000)
})
}
},
guards: {
isFilterUnchanged: ({ baseUrl, postBody }, { url, body }) => url === baseUrl && JSON.stringify(body) === JSON.stringify(postBody),
isPageCached: ({ pageCache }, { page }) => pageCache[page],
},
actions: {
setQueryString: (_, { url, body }) => {
// for illustration purposes
// save the url and params in
// the url to extract on refresh
location.search = `?baseUrl=${
encodeURIComponent(url)}?body=${
encodeURIComponent(JSON.stringify(body))
}`
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment