{"version":3,"file":"index.mjs","sources":["../../src/index.tsx"],"sourcesContent":["import * as React from 'react'\nimport useLatest from '@react-hook/latest'\n\nexport function useAsync<\n  ValueType extends any = any,\n  ErrorType extends any = Error,\n  Args extends any[] = any[]\n>(asyncCallback: (...args: Args) => Promise<ValueType>) {\n  const [state, dispatch] = React.useReducer<\n    React.Reducer<\n      AsyncReducerState<ValueType, ErrorType>,\n      AsyncAction<ValueType, ErrorType>\n    >,\n    undefined\n  >(\n    (prev, action) => ({\n      // This is the current status of the promise or async/await function. A\n      // promise or async/await can only be in one state at a time.\n      status: action.status,\n      // The value is persisted between 'success' statuses. This means I can\n      // still display things that depend on my current value while my new\n      // value is loading.\n      value: action.status === 'success' ? action.value : prev.value,\n      // Errors get reset each time we leave the error state. There's really\n      // no use in keeping those around. They go stale once we leave.\n      error: action.status === 'error' ? action.error : void 0,\n    }),\n    void 0,\n    () => {\n      return {\n        status: 'idle',\n        value: void 0,\n        error: void 0,\n      }\n    }\n  )\n  // Creates a stable callback that manages our loading/success/error status updates\n  // as the callback is invoked.\n  const storedCallback = useLatest(asyncCallback)\n\n  const [callback] = React.useState(() => {\n    const cancelled: Set<Promise<ValueType> | null> = new Set()\n    let previous: Promise<ValueType> | null\n\n    return Object.assign(\n      async (...args: Args) => {\n        // Reloading automatically cancels previous promises\n        cancelled.add(previous)\n        dispatch({status: 'loading'})\n        let current: Promise<ValueType> | null = null\n\n        try {\n          previous = current = storedCallback.current(...args)\n          const value = await current\n          !cancelled.has(current) && dispatch({status: 'success', value})\n        } catch (error) {\n          current &&\n            !cancelled.has(current) &&\n            dispatch({status: 'error', error})\n        } finally {\n          cancelled.delete(current)\n        }\n      },\n      {\n        cancel: () => {\n          cancelled.add(previous)\n        },\n      }\n    )\n  })\n\n  // Cancels any pending async callbacks when the hook unmounts\n  React.useEffect(() => callback.cancel, [callback])\n\n  return [\n    React.useMemo(() => {\n      return {\n        status: state.status,\n        value: state.value,\n        error: state.error,\n        cancel: () => {\n          // Prevent the callback from dispatching\n          callback.cancel()\n          // Create a new callback and set status to cancelled\n          dispatch({status: 'cancelled'})\n        },\n      }\n    }, [callback, state]),\n    callback,\n  ] as const\n}\n\nexport function useAsyncEffect<\n  ValueType extends any = any,\n  ErrorType extends any = Error\n>(\n  asyncCallback: () => Promise<ValueType>,\n  dependencies?: React.DependencyList\n) {\n  const [state, callback] = useAsync<ValueType, ErrorType>(asyncCallback)\n  // Runs the callback each time deps change\n  React.useEffect(() => {\n    callback()\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, dependencies)\n\n  return state\n}\n\nexport interface AsyncReducerState<ValueType, ErrorType> {\n  status: AsyncStatus\n  value?: ValueType\n  error?: ErrorType\n}\n\nexport type AsyncAction<ValueType, ErrorType> =\n  | {\n      status: 'idle' | 'loading' | 'cancelled'\n    }\n  | {\n      status: 'success'\n      value: ValueType\n    }\n  | {\n      status: 'error'\n      error?: ErrorType\n    }\n\nexport type AsyncStatus = 'idle' | 'loading' | 'success' | 'error' | 'cancelled'\n"],"names":["prev","action","status","value","error","useAsync","asyncCallback","callback","cancel","dispatch","state","React","storedCallback","useLatest","previous","cancelled","Set","Object","assign","add","current","has","delete","useAsyncEffect","dependencies"],"mappings":"4TAeI,WAACA,EAAMC,SAAY,CAGjBC,OAAQD,EAAOC,OAIfC,MAAyB,YAAlBF,EAAOC,OAAuBD,EAAOE,MAAQH,EAAKG,MAGzDC,MAAyB,UAAlBH,EAAOC,OAAqBD,EAAOG,WAAQ,GAGpD,mBACS,CACLF,OAAQ,OACRC,WAAO,EACPC,WAAO,GA7BR,SAASC,EAIdC,gBA2EQC,EAASC,SAETC,EAAS,CAACP,OAAQ,kBA5EnBQ,EAAOD,GAAYE,SAmBxB,KAWIC,EAAiBC,EAAUP,IAE1BC,GAAYI,EAAe,SAE5BG,EADEC,EAA4C,IAAIC,WAG/CC,OAAOC,UACZ,YAEEH,EAAUI,IAAIL,GACdL,EAAS,CAACP,OAAQ,gBACdkB,EAAqC,SAGvCN,EAAWM,EAAUR,EAAeQ,0BAC9BjB,QAAciB,GACnBL,EAAUM,IAAID,IAAYX,EAAS,CAACP,OAAQ,UAAWC,MAAAA,IACxD,MAAOC,GACPgB,IACGL,EAAUM,IAAID,IACfX,EAAS,CAACP,OAAQ,QAASE,MAAAA,YAE7BW,EAAUO,OAAOF,OAGrB,CACEZ,OAAQ,KACNO,EAAUI,IAAIL,eAOtBH,EAAgB,IAAMJ,EAASC,OAAQ,CAACD,IAEjC,CACLI,EAAc,KACL,CACLT,OAAQQ,EAAMR,OACdC,MAAOO,EAAMP,MACbC,MAAOM,EAAMN,MACbI,WAOD,CAACD,EAAUG,IACdH,GAIG,SAASgB,EAIdjB,EACAkB,OAEOd,EAAOH,GAAYF,EAA+BC,UAEzDK,EAAgB,KACdJ,KAECiB,GAEId"}