Call, observe and persist the result of your async functions with ease of `useCallback`!
npm install use-requestuseRequest(cb, options?)> Finally, easy way to use async functions in React

Call, observe, and persist the result of your async functions with the ease!
See how it works:
``tsx
const RandomNumberGenerator = () => {
const request = useRequest(() => api('/random-number'))
return (
Here is your random number: {request.value}
}Request failed due to: {request.error}
}Now, step-by-step:
Install
`bash
npm install --save use-request
`Usage
`tsx
import useRequest, { UseRequestStatus } from 'use-request'const Example = () => {
const request = useRequest(
callback, // Async function (can be sync if needed)
[] // Optional arguments list. The callback will be called immediately if this is set
)
// Results
request.value // Last result of the callback
request.error // Last error thrown from the callback
// Methods
request.execute(...callbackArgs) // Proxy to trigger the callback()
request.reset() // Drop the state and cancel ongoing requests
// Lifecycle
request.idle // True, when request is not initialized or was reset, use for initial screen
request.pending // True, when the request is ongoing, use to show spinners, disabled forms, etc.
request.completed // True, when the request is successfully resolved
request.failed // True, when the request is rejected
request.status // Value of UseRequestStatus enum, helpful for tracking request status
// ...
}
`$3
`tsx
function SaveButton() {
const request = useRequest(() => api('/save')) return
}
`$3
`tsx
function useUserData() {
const request = useRequest(() => api('/user'), []) return request.value
}
`$3
`tsx
function useUserData(userId) {
const request = useRequest((id) => api(/user/${id}), [userId]) return request.value
}
`$3
`tsx
const RemoveButton = (id) => {
const request = useRequest((itemId) => api.delete(/items/${itemId})) return
}
`$3
`tsx
const Button = ({ label, callback }) => {
const request = useRequest(callback) return (
)
}
`Options Object Syntax
Instead of passing an array as the second argument, you can pass an options object:
`tsx
const request = useRequest(callback, {
deps: [userId], // Dependencies array (triggers immediate execution)
optimisticValue: (value, ...args) => expectedValue, // Optimistic update value
})
`This is backwards compatible - arrays still work as before.
Patching State
You can manually update the request state using
patch() and patchValue():$3
Update just the value:
`tsx
const request = useRequest(fetchItems, [])// Add an item optimistically
const addItem = (newItem) => {
request.patchValue((items) => [...items, newItem])
api.addItem(newItem).catch(() => request.resetPatch())
}
`$3
Update the entire state (replaces, does not merge):
`tsx
// Set both value and error
request.patch({ value: newValue, error: undefined })// Clear value, set error
request.patch({ error: 'Something went wrong' })
// Use function form to derive from current state
request.patch((current) => ({ value: transform(current.value) }))
`$3
Restore the last real state from the server:
`tsx
const request = useRequest(fetchItems, [])request.patchValue([...items, optimisticItem])
// If something goes wrong:
request.resetPatch() // Restores to last server response
`$3
Track whether the current state is from a patch:
`tsx
request.patched // false | 'manual' | 'auto'// false - real data from request
// 'manual' - set via patch() or patchValue()
// 'auto' - set via optimisticValue option
`Example usage:
`tsx
{
request.patched && Saving...
}
`Optimistic Updates with
optimisticValueSet a value immediately when
execute() is called, before the request completes:`tsx
const useLike = (postId) => {
const request = useRequest(
(id, liked) => api.setLike(id, liked),
{
optimisticValue: (value, id, liked) => ({ liked }) // receives current value + spread args
}
) return request
}
// Usage
const { value, execute, patched } = useLike(postId)
`$3
When a request fails with
optimisticValue:- The patched value is kept (not rolled back)
- The error is set
-
patched remains 'auto'Use
resetPatch() to manually revert if needed:`tsx
if (request.failed && request.patched) {
// Show error with option to revert
return
}
`$3
If the
optimisticValue callback itself throws, the error is caught and:
- The current value is kept unchanged
- The error is set on the request
- Status becomes pending (the request still fires)
- patched is not set (no patch was applied)The request continues normally and will overwrite the error on success.
More Examples
$3
`tsx
const generateNumber = (max) =>
new Promise((resolve, reject) => {
if (max > 0) setTimeout(resolve, 2e3, Math.round(Math.random() * max))
else setTimeout(reject, 2e3, 'Max value must be greater than zero')
})const defaultMax = 100
const SingleFunctionExample = () => {
const [max, setMax] = React.useState('')
const { value, error, pending } = useRequest(
generateNumber, // Async function that returns promise
[max ? +max : defaultMax] // Initial arguments
)
return (
setMax(e.target.value)} />
{pending ? processing : null}
{value !== undefined ? Last result: {value} : null}
{error ? Error: {error} : null}
)
}
`$3
`tsx
const useResources = () => {
const { execute: reload, value: resources, status } = useRequest(api.get, [])
const { execute: create } = useRequest((resource) => api.post(resource).then(reload))
const { execute: remove } = useRequest((id) => api.delete(id).then(reload)) return { resources, status, create, remove }
}
const MultipleFunctionsExample = () => {
/* @type {React.MutableRefObject} /
const resourceLabelRef = useRef(null)
const { resources, status, create, remove } = useResources()
const onSubmit = (e) => {
e.preventDefault()
if (!resourceLabelRef.current) return
create({ label: resourceLabelRef.current.value })
resourceLabelRef.current.value = ''
}
return (
{!resources && status === UseRequestStatus.Pending ?
Loading...
: null} {resources ? (
{resources.map((res) => (
{res.label} remove(res.id)} value="remove" />
))}
) : null}
)
}
`$3
`tsx
const useTodos = () => {
const { value: todos, execute: refresh, patchValue, resetPatch } = useRequest(() => api.getTodos(), []) const addTodo = async (text) => {
const optimisticTodo = { id: Date.now(), text, completed: false }
patchValue((current) => [...(current || []), optimisticTodo])
try {
await api.addTodo(text)
refresh() // Get real data from server
} catch (e) {
resetPatch() // Revert on error
}
}
return { todos, addTodo }
}
`API Reference
$3
| Parameter | Type | Description |
| ---------- | ------------------------------ | ------------------------------------ |
|
callback | (...args) => Promise | Async function to execute |
| options | T[] \| Options \| null | Dependencies array or options object |#### Options object
| Property | Type | Description |
| ----------------- | ----------------------- | ---------------------------------------------------------- |
|
deps | T[] \| null | Dependencies array (triggers immediate execution when set) |
| optimisticValue | (value, ...args) => T | Value to set immediately on execute |$3
| Property | Type | Description |
| ------------ | ----------------------------- | -------------------------------- |
|
value | T \| undefined | Last successful result |
| error | E \| undefined | Last error |
| status | UseRequestStatus | Current status enum |
| idle | boolean | True when not yet executed |
| pending | boolean | True while request is in flight |
| completed | boolean | True after successful completion |
| failed | boolean | True after error |
| patched | false \| 'manual' \| 'auto' | Patch state indicator |
| execute | (...args) => Promise | Trigger the request |
| reset | () => void | Reset to idle state |
| patch | (input) => void | Update state manually |
| patchValue | (input) => void | Update value only |
| resetPatch | () => void` | Restore last real state |MIT © termosa
---
This hook is created using create-react-hook.