Skip to content

Instantly share code, notes, and snippets.

@aadityataparia
Last active November 15, 2021 09:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aadityataparia/2d663db0827d39164dcd748468968bdb to your computer and use it in GitHub Desktop.
Save aadityataparia/2d663db0827d39164dcd748468968bdb to your computer and use it in GitHub Desktop.
Async callback and effect hooks for React in JS and TS
import { useCallback, useState, useEffect } from 'react'
const defaultState = { error: null, isLoading: false, result: null }
export const useAsyncCallback = (callback, deps = []) => {
const [state, setState] = useState(defaultState)
const cb = useCallback(
(...args) => {
const req = callback(...args)
setState({ error: null, isLoading: true, result: null })
req.then(result => {
setState({ error: null, isLoading: false, result })
return result
}).catch(error => {
setState({ error, isLoading: false, result: null })
throw error
})
return req
},
// eslint-disable-next-line react-hooks/exhaustive-deps
deps
)
return {
...state,
callback: cb,
}
}
export const useAsyncEffect = (callback, deps) => {
const returnValues = useAsyncCallback(callback, deps)
useEffect(() => {
returnValues.callback()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps)
return returnValues
}
/*
Usage:
const { isLoading, callback, error, result } = useAsyncCallback(
() =>
fetch(a, b),
[a, b]
);
*/
import { useCallback, useState, useEffect } from 'react';
export type AsyncHookCallback<T> = (...args: any[]) => Promise<T>;
export type AsyncHookResult<T> = {
error: Error | null;
result: T | null;
isLoading: boolean;
callback: AsyncHookCallback<T>;
};
const defaultState = { error: null, isLoading: false, result: null };
/*
useCallback hook for async functions.
Usage:
const { isLoading, callback, error, result } = useAsyncCallback(
() =>
fetch(a, b),
[a, b]
);
*/
export const useAsyncCallback = <T>(callback: AsyncHookCallback<T>, deps = []): AsyncHookResult<T> => {
const [state, setState] = useState(defaultState);
const cb = useCallback(
(...args) => {
const req = callback(...args);
setState({ error: null, isLoading: true, result: null });
req.then(result => {
setState({ error: null, isLoading: false, result });
return result;
}).catch(error => {
setState({ error, isLoading: false, result: null });
throw error;
});
return req;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
deps,
);
return {
...state,
callback: cb,
};
};
/*
useEffect hook for async functions.
Usage:
const { isLoading, callback, error, result } = useAsyncEffect(
() =>
fetch(a, b),
[a, b]
);
*/
export const useAsyncEffect = <T>(callback: AsyncHookCallback<T>, deps: any[]): AsyncHookResult<T> => {
const returnValues = useAsyncCallback(callback, deps);
useEffect(() => {
returnValues.callback();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
return returnValues;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment