You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
spa_instat_tv/src/hooks/useRequest.tsx

78 lines
1.9 KiB

import { useState, useCallback } from 'react'
/**
* Хук для состояния загрузки и ошибки.
* Возвращает isFetching и switchState для переключения состояния
* switchState слушает Promise и завершает загрузку при завершении Promise
*/
const useRequestState = () => {
const [isFetching, setFetchingState] = useState(false)
const [error, setError] = useState<Error | null>(null)
const switchState = useCallback(
(promise: Promise<unknown>) => {
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 (
* <div>
* {isFetching && 'Loading...'}
* ...
* </div>
* )
* ```
*/
export const useRequest = <
F extends (...args: any) => Promise<unknown>,
>(asyncFunction: F) => {
const {
error,
isFetching,
switchState,
} = useRequestState()
const request = useCallback(
(...args: Parameters<F>) => (
switchState(asyncFunction(...args)) as ReturnType<F>
),
[switchState, asyncFunction],
)
return {
error,
isFetching,
request,
}
}