Skip to content

Instantly share code, notes, and snippets.

@VitorLuizC
Created April 7, 2020 18:36
Show Gist options
  • Save VitorLuizC/ead5e87bbb9da3ec577380e3c31ca3ec to your computer and use it in GitHub Desktop.
Save VitorLuizC/ead5e87bbb9da3ec577380e3c31ca3ec to your computer and use it in GitHub Desktop.
import { useCallback, useEffect, useRef, useState } from 'react';
/**
* @typedef State
* @property {null | Error} error
* @property {null | T} result
* @property {boolean} loading
* @template T
*/
/**
* @param {function():Promise.<T>} task
* @param {boolean} [immediate]
* @template T
* @returns {[function():Promise.<T>, State.<T>]}
*/
const useTask = (task, immediate = true) => {
const mountedRef = useRef(true);
const [state, setState] = useState({
error: null,
result: null,
loading: immediate
});
/**
* @type {function(T):Promise.<T>}
*/
const handleResolve = useCallback(result => {
if (mountedRef.current) {
setState({
result,
error: null,
loading: false
});
}
return Promise.resolve(result);
}, []);
/**
* @type {function(Error):Promise.<never>}
*/
const handleReject = useCallback(error => {
if (mountedRef.current) {
setState({
error,
result: null,
loading: false
});
}
return Promise.reject(error);
}, []);
/**
* @returns {Promise.<T>}
*/
const runTask = useCallback(() => {
setState(state => ({ ...state, loading: true }));
return task()
.then(handleResolve)
.catch(handleReject);
}, [task]);
useEffect(() => {
if (immediate) runTask();
return () => {
mountedRef.current = false;
};
}, []);
return [runTask, state];
};
export default useTask;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment