UNPKG

@react-hookz/web

Version:

React hooks done right, for browser and SSR.

86 lines (85 loc) 3.33 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { useMemo, useRef } from 'react'; import { useSafeState, useSyncedRef } from '..'; /** * Tracks result and error of provided async function and provides handles to execute and reset it. * * @param asyncFn Function that returns a promise. * @param initialValue Value that will be set on initialisation, before the async function is * executed. */ export function useAsync(asyncFn, initialValue) { var _a = useSafeState({ status: 'not-executed', error: undefined, result: initialValue, }), state = _a[0], setState = _a[1]; var promiseRef = useRef(); var argsRef = useRef(); var methods = useSyncedRef({ execute: function () { var params = []; for (var _i = 0; _i < arguments.length; _i++) { params[_i] = arguments[_i]; } argsRef.current = params; var promise = asyncFn.apply(void 0, params); promiseRef.current = promise; setState(function (s) { return (__assign(__assign({}, s), { status: 'loading' })); }); // eslint-disable-next-line promise/catch-or-return promise.then(function (result) { // we dont want to handle result/error of non-latest function // this approach helps to avoid race conditions // eslint-disable-next-line promise/always-return if (promise === promiseRef.current) { setState(function (s) { return (__assign(__assign({}, s), { status: 'success', error: undefined, result: result })); }); } }, function (error) { // we dont want to handle result/error of non-latest function // this approach helps to avoid race conditions if (promise === promiseRef.current) { setState(function (s) { return (__assign(__assign({}, s), { status: 'error', error: error })); }); } }); return promise; }, reset: function () { setState({ status: 'not-executed', error: undefined, result: initialValue, }); promiseRef.current = undefined; argsRef.current = undefined; }, }); return [ state, useMemo(function () { return ({ reset: function () { methods.current.reset(); }, execute: function () { var _a; var params = []; for (var _i = 0; _i < arguments.length; _i++) { params[_i] = arguments[_i]; } return (_a = methods.current).execute.apply(_a, params); }, }); }, // eslint-disable-next-line react-hooks/exhaustive-deps []), { promise: promiseRef.current, lastArgs: argsRef.current }, ]; }