useAsyncFn
Wrap an async function to get loading, error and result state, ignoring results of outdated calls.
Use useAsyncFn when a button or form runs an async action and you need a loading flag, the result or the error, without writing that state yourself.
Example
import { useAsyncFn } from '@salla.sa/twilight-theme-engine/hooks/useAsyncFn';
export function SaveForLater({ productId }: { productId: number }) {
const [state, save] = useAsyncFn(async () => {
await window.salla?.wishlist.add(productId);
return true;
}, [productId]);
return (
<button onClick={() => save()} disabled={state.loading}>
{state.value ? 'Saved' : 'Save for later'}
</button>
);
}It returns a pair: the current state, and a wrapped version of your function. Call the wrapped function to run the action.
API
function useAsyncFn<T extends (...args: never[]) => Promise<unknown>>(
fn: T,
deps?: DependencyList,
initialState?: AsyncState<Awaited<ReturnType<T>>>
): [AsyncState<Awaited<ReturnType<T>>>, T];| Prop | Type | Description |
|---|---|---|
fn | T | The async function to wrap. Required. |
deps? | DependencyList | Values fn reads, like the dependencies of useCallback. Default: []. |
initialState? | AsyncState | Starting state. Default: { loading: false }. |
The state has loading: boolean, and then value after success or error after failure.
Gotchas
When fn rejects, the wrapped function does not throw. It resolves with the error, and state.error is set. Check state.error or result instanceof Error instead of using try/catch.
depsdefaults to[], so the wrapped function keeps the firstfnit saw. Pass every valuefnreads, as in the example.- Only the latest call updates the state. Results of older, slower calls are ignored.
- State is not updated after the component unmounts.
Next
useWishlistis built on this hook.- Loading data covers data that belongs in a route loader instead.
- Salla SDK and events lists the
Salla.*calls you will wrap.