github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/dashboard/frontend/src/hooks/useApiData.ts (about) 1 import { useState, useEffect, useCallback } from 'react' 2 import bluebird from 'bluebird' 3 import useApi from './useApi' 4 import { logger } from '../utils/debug' 5 6 export function useApiData<DataType = any>({ 7 url, 8 defaultValue, 9 active = true, 10 reload = false, 11 reloadInterval = 5000, 12 jsonStringifyComparison = true, 13 onChange = () => {}, 14 }: { 15 url: string, 16 defaultValue: DataType, 17 active?: boolean, 18 reload?: boolean, 19 reloadInterval?: number, 20 // if this is set to false - we use JSON.stringify comparison 21 // and don't update the state if equal 22 jsonStringifyComparison?: boolean, 23 onChange?: { 24 (data: DataType): void, 25 } 26 }): [DataType, { 27 (): Promise<void>, 28 }] { 29 30 const api = useApi() 31 const [data, setData] = useState<DataType>(defaultValue) 32 33 const fetchData = useCallback(async () => { 34 const apiData = await api.get<DataType>(url) 35 if (apiData === null) return 36 // only update the state if the data is different 37 // this prevents re-renders whilst loading data in a loop 38 setData(currentValue => { 39 if(!jsonStringifyComparison) return apiData 40 const hasChanged = JSON.stringify(apiData) != JSON.stringify(currentValue) 41 if(hasChanged && onChange) onChange(apiData) 42 return hasChanged ? 43 apiData : 44 currentValue 45 }) 46 }, [ 47 url, 48 ]) 49 50 useEffect(() => { 51 if(!active) return 52 if(!reload) { 53 fetchData() 54 return 55 } 56 let loading = true 57 const doLoop = async () => { 58 while(loading) { 59 await fetchData() 60 await bluebird.delay(reloadInterval) 61 } 62 } 63 doLoop() 64 return () => { 65 loading = false 66 } 67 }, [ 68 active, 69 url, 70 ]) 71 72 useEffect(() => { 73 logger('useApiData', url, data) 74 }, [ 75 data, 76 ]) 77 78 return [data, fetchData] 79 } 80 81 export default useApiData