|
| 1 | +# useAsync |
| 2 | + |
| 3 | +A hook to manage state of any asynchronous operation. This hook can be used to manage `loading`, `data` and `error` states of an asynchronous operation. It is mainly used for data fetching, the first argument to the hook is the function that fetches and returns data, required options is the second argument and dependencies is the last argument. |
| 4 | + |
| 5 | +Only the most recent promise is considered in this hook, meaning you don't need to worry about any api race conditions could arise because of out of order responses from multiple api calls. In case of error the data will be of previous call or null. |
| 6 | + |
| 7 | +<pre>{`import { useAsync } from 'react-use-custom-hooks';`}</pre> |
| 8 | + |
| 9 | +### Usage example |
| 10 | + |
| 11 | +```typescript |
| 12 | +const [data, loading, error, refresh] = useAsync(() => fetchTodo(id), {}, [id]); |
| 13 | +``` |
| 14 | + |
| 15 | +The fourth return value is a function to execute the operation again forcefully without any dependance change, like a refresh. |
| 16 | + |
| 17 | +```typescript |
| 18 | +<button onClick={() => refresh()}>Retry</button> |
| 19 | +``` |
| 20 | + |
| 21 | +### Playground |
| 22 | + |
| 23 | +The component will fetch and show the todo based on the id, when ever the id changes the component will fetch the todo corresponding to the id. If there is any error in data fetching we will show the error message with a retry button. User can retry the last failed request by clicking the retry button. |
| 24 | + |
| 25 | +```jsx live |
| 26 | +function AsyncExample(props) { |
| 27 | + const [id, setId] = React.useState(1); |
| 28 | + |
| 29 | + // Move this to a service function |
| 30 | + function fetchTodo(id) { |
| 31 | + return fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) |
| 32 | + .then(response => response.json()) |
| 33 | + .then(json => json); |
| 34 | + } |
| 35 | + |
| 36 | + // if id changes, data will be fetched for the new id |
| 37 | + const [data, loading, error, refresh] = useAsync(() => fetchTodo(id), {}, [ |
| 38 | + id, |
| 39 | + ]); |
| 40 | + if (loading) return <div>Loading...</div>; |
| 41 | + if (error) |
| 42 | + return ( |
| 43 | + <div> |
| 44 | + Error: {error.message} |
| 45 | + // User can retry on error without page refresh |
| 46 | + <button onClick={() => refresh()}>Retry</button> |
| 47 | + </div> |
| 48 | + ); |
| 49 | + |
| 50 | + return ( |
| 51 | + <> |
| 52 | + <p> |
| 53 | + Id - <b>{id}</b> |
| 54 | + </p> |
| 55 | + <p> |
| 56 | + Data - <b>{JSON.stringify(data)}</b> |
| 57 | + </p> |
| 58 | + <button onClick={() => setId(id => id + 1)}>++ Id</button> |
| 59 | + <button |
| 60 | + style={{ marginLeft: '10px' }} |
| 61 | + onClick={() => setId(id => id - 1)} |
| 62 | + > |
| 63 | + -- Id |
| 64 | + </button> |
| 65 | + </> |
| 66 | + ); |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +Only the most recent promise is considered in this hook, For example, in the above component there is a chance of race condition as depicted below. |
| 71 | + |
| 72 | +1. Currently id is 123 and fetching details of id is 123 |
| 73 | +2. Then id changes to 465 while request for 123 is in progress and initiated request for 456 |
| 74 | +3. Response for 456 came back, state is updated with 456 data |
| 75 | +4. Response for 123 came back, state is updated with 123 data |
| 76 | + |
| 77 | + Here the UI will show 123 data even though the user selected 456 as id. This hook will take care of this issue by keeping only the most recent promise in the state by ignoring the current one if a new request is triggered. |
| 78 | + |
| 79 | +### API |
| 80 | + |
| 81 | +```typescript |
| 82 | +function useAsync(fn: () => Prm, options?: Options, deps = []); |
| 83 | +``` |
| 84 | + |
| 85 | +#### Options |
| 86 | + |
| 87 | +| Property | Description | Type | Default | |
| 88 | +| --------------- | ---------------------------- | ---------- | ------- | |
| 89 | +| successCallback | Callback function on success | `Function` | - | |
| 90 | +| errorCallback | Callback function on failure | `Function` | - | |
0 commit comments