https://github.com/azmenak/use-async-call
Provides a hook to manage the state and lifecycle of async data loading
https://github.com/azmenak/use-async-call
async react react-hooks typescript usereducer
Last synced: 5 months ago
JSON representation
Provides a hook to manage the state and lifecycle of async data loading
- Host: GitHub
- URL: https://github.com/azmenak/use-async-call
- Owner: azmenak
- Created: 2019-03-21T03:23:23.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2023-01-03T18:14:32.000Z (over 3 years ago)
- Last Synced: 2025-08-09T18:30:18.272Z (10 months ago)
- Topics: async, react, react-hooks, typescript, usereducer
- Language: TypeScript
- Homepage:
- Size: 912 KB
- Stars: 11
- Watchers: 2
- Forks: 0
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# use-async-call

[](https://codecov.io/gh/azmenak/use-async-call)
[](https://travis-ci.org/azmenak/use-async-call)

Provides an abstraction over the lower-level [`use-async-reducer`](https://github.com/azmenak/use-async-reducer), handles calls to `useEffect` and handles cancelation when the inputs change or components unmounts to avoid modifying stale data
## Install
```
npm install use-async-call
```
## Usage
```ts
import useAsyncCall from 'use-async-call'
const [state, {update, refresh, actions}] = useAsyncCall(
asyncCreator,
(options = {})
)
```
### Demo
[](https://codesandbox.io/s/mo51y75rzx?fontsize=14)
### Params
- `asyncCreator` An async method (returns a promise), create this method with `useCallback` if it depends on state from the component
```ts
const [searchText, setSearchText] = useState('')
const fetchData = useCallback(() => Api.search(searchText), [searchText])
```
- `options`
```ts
interface UseAsyncCallOptions {
/**
* Initial value used for `data` of state
*/
initialValue?: T
/**
* When true, will not call `actions.initalize` when `asyncCreator` updates
* This keeps the data in the store between updates, useful when the identity
* of the data does not belong to the inputs, example would be a search
* component that uses "search text" as an input
*/
dontReinitialize?: boolean
/**
* Callback called after call is successful
* @param data Data returned from async caller
*/
onSuccess?(data?: T): void
/**
* Callback called after async call throws
* @param error Error thrown by async caller
*/
onFailure?(error?: Error): void
/**
* Callback always called after async call completes
*/
onComplete?(): void
}
```
### Return values
- `state` an object containing state of async call
```ts
const state: Loadable = {
data: {}, // any data
loading: false, // true when calls in progress
error: null // instance of Error if calls throw
}
```
- `update(asyncUpdater, updateOptions = {})` method used to update the state
- `asyncUpdater` either a promise or a method which returns a promise, the result will be set to the `data` value of the state
- `updateOptions`
```ts
interface UseAsyncCallUpdateOptions {
/**
* Should thrown errors be re-thrown in the resulting promise from `update`;
* useful when using in conjuction with form libraries that expect errors
* when submitting form values
*/
throwError?: boolean
/**
* If the caller throws, sets `state.error` to the error and `state.data` to
* `null`
*/
saveError?: boolean
/**
* Callback called after call is successful
* @param data Data returned from async caller
*/
onSuccess?(data?: T): void
/**
* Callback called after async call throws
* @param error Error thrown by async caller
*/
onFailure?(error?: Error): void
/**
* Callback always called after async call completes
*/
onComplete?(): void
}
```
- `refresh` method used to re-call the method passed to `useAsyncCall`
- `actions` action methods created by [`use-async-reducer`](https://github.com/azmenak/use-async-reducer)
```ts
interface AsyncReducerBoundActions {
/**
* To be called at the beginning of a request, sets `loading` to `true`
*/
request(): void
/**
* To be called with the data to be saved into the state
* @param payload Result of the async call
*/
success(payload: T): void
/**
* To be called when the async call fails
* @param error
*/
failure(error: Error): void
/**
* Can be called when a call fails/complete and the result is being discarded
*/
complete(): void
}
```
## Examples
### Basic Example
```tsx
import React, {useCallback} from 'react'
import useAsyncCall from 'use-async-call'
import Api from './custom-api'
const DataLoadingComponent: React.FC<{id: number}> = ({id}) => {
const fetchData = useCallback(() => Api.fetchModelData(id), [id])
const [model] = useAsyncCall(fetchData)
// model is now managed, it will automatically fetch new data when `id` prop
// changes and update the state to reflect any changes
}
```
### A component which updates a value at an API
```tsx
import React, {useCallback} from 'react'
import useAsyncCall from 'use-async-call'
import Api from './custom-api'
interface User {
id: number
name: string
}
const UserProfile: React.FC<{userId: number}> = ({userId}) => {
const [name, setName] = useState('')
const fetchUser = useCallback(() => Api.fetchUserById(userId), [userId])
const [user, {update: updateUser}] = useAsyncCall(fetchUser)
const handleUpdateUserName = useCallback((): Promise => {
return Api.updateUser(userId, {name})
}, [userId, name])
return (
User: {userId}
{user.loading && Loading...}
{user.data && {user.data.name}}
{user.error && {user.error.message}}
{user.data && (
<>
setName(event.target.value)}
/>
updateUser(handleUpdateUserName)}
>
Update Name
>
)}
)
}
```
### Create a custom hook to load and update a model
```ts
import {useCallback} from 'react'
import useAsyncCall, {Loadable} from 'use-async-call'
import Api from './custom-api'
interface User {
id: number
name: string
}
export function useUserData(
userId: number
): [Loadable, (userData: Partial) => Promise] {
const fetchUser = useCallback(() => Api.fetchUserById(userId), [userId])
const [user, {update: updateUser}] = useAsyncCall(fetchUser)
}, [])
const handleUpdateUser = useCallback(
(userData: Partial) => {
return updateUser(Api.updateUser(userId, userData), {
onSuccess() {
alert('Updated user!')
},
onFailure() {
alert('Failed to update user')
}
})
},
[userId]
)
return [user, handleUpdateUser]
}
```
### Get Data from a Search API
```tsx
import React, {useCallback, useState} from 'react'
import useAsyncCall from 'use-async-call'
import SearchApi from './search-api'
export function useSearchData(searchText: string) {
const fetchData = useCallback(() => SearchApi.find(searchText), [searchText])
return useAsyncCall(fetchData, {dontReinitialize: true})
}
const SearchComponent: React.FC = () => {
const [searchText, setSearchText] = useState('')
const [searchData] = useSearchData(searchText)
return (
<>
{
setSearchText(event.target.value)
}}
/>
{searchData.data && (
<>
Search Results
- {searchResult.name}
{searchData.data.map((searchResult) => (
))}
>
)}
>
)
}
```