const allowRetry = (retries, maxRetries) => retries < maxRetries; const FetchMachine = Machine({ id: "fetch", initial: "idle", context: { request: null, data: null, error: null, retries: 0, maxRetries: 0, }, states: { idle: { on: { FETCH: "pending", }, }, pending: { invoke: { src: "fetch", onDone: { target: "success", actions: ["setData", "notifySuccess"], }, onError: { target: "failure", actions: ["setError", "notifyError"], }, }, }, failure: { on: { "": { target: "finalFailure", cond: "canNotRetry", }, RETRY: { target: "pending", actions: "incrementRetries", }, }, }, finalFailure: { on: {}, type: "final", }, success: { on: { REFRESH: { target: "pending", actions: "resetRetries", }, }, }, }, }, { guards: { canNotRetry: ({ retries, maxRetries }) => !allowRetry(retries, maxRetries), }, actions: { setData: assign({ data: (_, event) => event.data }), setError: assign({ error: (_, event) => event.data.message }), incrementRetries: assign({ retries: context => context.retries + 1 }), resetRetries: assign({ retries: context => 0 }), notifySuccess: context => { }, notifyError: context => { }, }, services: { fetch: async ({ request }) => { if (!request) { throw new Error("Machine must receive a valid request object in context"); } const response = await request(); return response.data; }, }, });