import { useState, useCallback } from 'react' /** * Хук для состояния загрузки и ошибки. * Возвращает isFetching и switchState для переключения состояния * switchState слушает Promise и завершает загрузку при завершении Promise */ const useRequestState = () => { const [isFetching, setFetchingState] = useState(false) const [error, setError] = useState(null) const switchState = useCallback( (promise: Promise) => { setFetchingState(true) setError(null) return promise .catch((err) => { setError(err) return Promise.reject(err) }) .finally(() => setFetchingState(false)) }, [], ) return { error, isFetching, switchState, } } /** * Хук для состояния загрузки. * Получает asyncFunction функция возвращающая Promise * и возвращает функцию обертку над asyncFunction * * Загрузка начинается при вызове обертки, заканчивается при завершении Promise * * ```ts * const [countries, setCountries] = useState([]) * * const { request: fetchCountries, isFetching } = useRequest(getCountries) * * useEffect(() => { * fetchCountries().then(setCountries) * }, []) * * return ( *
* {isFetching && 'Loading...'} * ... *
* ) * ``` */ export const useRequest = < F extends (...args: any) => Promise, >(asyncFunction: F) => { const { error, isFetching, switchState, } = useRequestState() const request = useCallback( (...args: Parameters) => ( switchState(asyncFunction(...args)) as ReturnType ), [switchState, asyncFunction], ) return { error, isFetching, request, } }