diff --git a/README.md b/README.md index 28f8e8b..3775090 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ ## React Use Async Fn -React hook for managing the state of an async function +React hook for managing the state of async function and abortable async functions + +### Features +- Execute and track not only API requests but any async functions. +- Abort async functions. Can be used to abort fetch API calls. +- Simple API to `await` async function to get its result while the hook manages the state. +- Callbacks for notifying success and error ### Installing @@ -33,36 +39,9 @@ import { useAsync, STATES } from "react-use-async-fn"; #### Basic example: ```js -import { useCallback } from 'react' -import { useAsync, STATES } from 'react-use-async-fn'; - -const sleep = () => new Promise(r => setTimeout(r, 5000)) - -function App() { - const getData = useCallback(async (input: number) => { - await sleep(); - return input + 1; - }, []); - const [{ data, error, status}, trigger] = useAsync({ fn: getData, }); - - return ( -
-

data

-

{data}

-

status

-

{status}

-

error

-

{error as string}

- -
- ) -} - -export default App - ``` You can provide your async function through the `fn` prop. @@ -81,7 +60,9 @@ const onClick = async () => { ### API -useAsync(props) +#### useAsync + +This hook manages the state of execution of an async function **props:** `fn`: Async function to track and execute. @@ -93,18 +74,135 @@ Array of state, trigger. `[state, trigger]` `state.data`: The return value of the `fn`. Initially `null`. -`state.status`: `STATUS` of the function. One of [`INITIAL`, `WORKING`, `DONE`, `FAILED`] +`state.status`: [Status](#STATUSES) of the function. One of [`INITIAL`, `WORKING`, `DONE`, `FAILED`] `state.error`: The error thrown by the `fn`. Initially `null`. `state.isLoading`: boolean. `true` if `state.status` is `STATUS.WORKING`. -`trigger`: Function to call the provided `fn`. All arguments are forwarded to the `fn`. +`trigger`: Function to call the provided `fn`. All arguments are forwarded to the `fn`. You can `await` the trigger to get the output of `fn`. + + +#### useAbortableAsync(props) + +This function manages the state of an async function which can be aborted. + +The `fn` prop requires the last argument to be of `AbortableLifecycle` to use this hook. + +**props** + +`fn`: `(...any[], { abortSignal: AbortSignal }) => Promise` Async function to track and execute. + +Other props are same as [useAsync](#useAsync). + + +**returns** -**STATUS:** +Array of state, actions +`[state, { trigger, abort }]` + +`state`: same as `[useAsync](#useAsync)`. +`trigger`: function which takes all arguments for `fn`, execpt the last argument [AbortableLifecycle](#AbortableLifecycle). The `AbortableLifecycle` argument is automatically injected by the hook. +`abort`: function to abort the request. + + +#### STATUSES + +Enum of statuses + +`INITIAL`: The status before triggering +`WORKING`: The status after triggering but before completion +`DONE`: The status when completed successfully +`FAILED`: The status when failed + +#### AbortableLifecycle +The last argument of an `AbortableAsyncFn`. It has the shape of +``` + { + abortSignal: AbortSignal, + } +``` + +### Examples: + +#### useAsync: ```js -STATES = { - INITIAL: "INITIAL", - WORKING: "WORKING", - DONE: "DONE", - FAILED: "FAILED", -}; +import { useCallback } from 'react' +import { useAsync, STATUSES } from 'react-use-async-fn'; + +const sleep = () => new Promise(r => setTimeout(r, 5000)) + +function App() { + const getData = useCallback(async (input: number) => { + await sleep(); + return input + 1; + }, []); + + const [{ data, error, status}, trigger] = useAsync({ + fn: getData, + }); + + return ( +
+

data

+

{data}

+

status

+

{status}

+

error

+

{error as string}

+ +
+ ) +} + ``` + +#### useAbortableAsync + +```js +import { useCallback } from 'react' +import { AbortableLifecycle, STATUSES, useAbortableAsync } from 'react-use-async-fn'; + +function abortbleSleep(ms=5000, {abortSignal}: AbortableLifecycle): Promise{ + return new Promise((resolve, reject) => { + console.log("Promise Started"); + + let timeout: ReturnType; + + const abortHandler = () => { + clearTimeout(timeout); + reject(new Error("Aborted")); + } + + // start async operation + timeout = setTimeout(() => { + resolve("Promise Resolved"); + abortSignal?.removeEventListener("abort", abortHandler); + }, ms); + + abortSignal?.addEventListener("abort", abortHandler); + }); +} + +function App() { + const [{ data, error, status }, {trigger, abort}] = useAbortableAsync({ + fn: abortbleSleep, + }); + + return ( +
+

Abortable

+

data

+

{data}

+

status

+

{status}

+

error

+

{(error as Error)?.message}

+

+ +

+

+ +

+
+ ) +} +``` \ No newline at end of file