useStandardApiV2
Questo hook permette di eseguire chiamate alle Standard Api V2.
Firma della funzione
function useStandardApiV2<BASE_OBJ, RESPONSE_OBJ, INCLUDED_BASE_OBJ, INCLUDED_RES_OBJ, POSTPROCESS_RES_OBJ = undefined>(
stdApiProp: IStdApi<BASE_OBJ, RESPONSE_OBJ, INCLUDED_BASE_OBJ>,
dependencies: DependencyList = [],
options?: Options<POSTPROCESS_RES_OBJ>
): useStandardApiV2ReturnType<RESPONSE_OBJ, INCLUDED_RES_OBJ>- stdApiProp: oggetto che definisce la chiamata API (required)
- dependencies: array di dipendenze che al loro variare scatenano una nuova chiamata API (opzionale)
- options: opzioni di configurazione (opzionale)
Opzioni di configurazione
Il parametro options fa riferimento a questo tipo:
type Options<POSTPROCESS_RES_OBJ> = {
fetchOnFirstRender?: boolean
refreshOnDepChange?: boolean
debounce?: number
enableDebounce?: boolean
appendData?: boolean
errorMessage?: string
onFiltersChange?: () => void
onSortChange?: () => void
shouldFetchCallback?: () => boolean
postProcess?: (...args: any[]) => POSTPROCESS_RES_OBJ
}- fetchOnFirstRender: determina se al primo render eseguire subito una chiamata API
- refreshOnDepChange: determina se al variare di una o piu dipendenze eseguire una chimata API
- debounce: tempo di debounce di una chimata API (default = 150ms) se enableDebounce = true
- enableDebounce: determina se abilitare o meno il debounce delle chiamate (default = true)
- appendData: determina se aggiungere i dati di ogni chiamata all’interno di un buffer in append (con controllo duplicati su chiave
key) - errorMessage: il testo da mostrare nel toast d’errore in caso di una risposta negativa da parte dell’API
- onFiltersChange: funzione da eseguire quando uno o piu filtri all’interno di
stdApiPropvaria - onSortChange: come
onFiltersChangema per l’ordinamento - shouldFetchCallback: callback che viene eseguita prima di ogni chiamata API (debounce o meno) per determinare se la chiamata puo essere eseguita
- postProcess: applica una trasformazione ai dati ritornati dalla chiamata API
Valori di ritorno
Questo hook ritorna i seguenti valori:
type useStandardApiV2ReturnType<RESPONSE_OBJ, INCLUDED_RES_OBJ> = {
value: ApiResponse<RESPONSE_OBJ, INCLUDED_RES_OBJ>
loading: boolean
refresh: () => void
refreshDebounce: () => void
cancelDebounce: () => void
isReadyDebounce: boolean | null
resetAppend: () => void
}- value: oggetto che contiene la response base, la zip response, lastQuery, responseCode, appendedZipResponse (buffer in append), postProcessedData (dati trasformati tramite funzione
postProcess) - loading: stato che indica se la chiamata è in corso
- refresh: funzione che esegue la chimata API
- refreshDebounce: come refresh ma in debounce
- cancelDebounce: ferma il debounce se in corso
- isReadyDebounce: determina lo stato del debounce (true: debounce in corso, false: debounce non ancora partito, null: debounce inattivo)
- resetAppend: svuota il buffer con in dati in append
Logica di funzionamento
Configurazione di default
Viene eseguito il destruct dell’oggetto options in input, se alcune option non esistono vengono impostate di default come segue:
const {
fetchOnFirstRender = true,
refreshOnDepChange = true,
appendData = false,
errorMessage = "errore_generico",
onFiltersChange = undefined,
onSortChange = undefined,
postProcess = undefined,
debounce = 150,
enableDebounce = true,
shouldFetchCallback = undefined
} = options ?? {}shouldFetchCallback
Funzione di controllo shouldFetchCallback se presente, se non presente ritorna sempre true in modo da poter eseguire chiamate API\
const checkShouldFetchCbAndCallApi = () => {
if (shouldFetchCallback) {
return shouldFetchCallback()
} else {
return true
}
}Debounce
Controlla checkShouldFetchCbAndCallApi e poi esegue refresh con logica di debounce\
const [isReady, cancel, reset] = useTimeoutFn(() => {
checkShouldFetchCbAndCallApi() && refresh()
}, debounce)
Refresh e RefreshDebounce
internalRefresh è la funzione che esegue il refresh controllando prima il risultato di checkShouldFetchCbAndCallApi
internalRefreshDebounce è la funzione che esegue il refresh in debounce, in questo caso il controllo di checkShouldFetchCbAndCallApi è dentro al debounce
const internalRefresh = () => {
checkShouldFetchCbAndCallApi() && refresh()
}
const internalRefreshDebounce = () => {
reset()
}Buffer in append e funzioni onFiltersChange & onSortChange
Svuota automaticamente il buffer in append se un filtro o un ordinamento è cambiato rispetto ad una chiamata precedente
Controlla solo filtri e ordinamento
const oldApiProps = useRef<IStdApi<BASE_OBJ, RESPONSE_OBJ, INCLUDED_BASE_OBJ> | undefined>()
const oldFilters = JSON.stringify(oldApiProps?.current?.filters)
const oldSorting = JSON.stringify(oldApiProps?.current?.sorting)
const newFilters = JSON.stringify(stdApiProp.filters)
const newSorting = JSON.stringify(stdApiProp.sorting)
useEffect(() => {
if (oldFilters !== newFilters) {
onFiltersChange && onFiltersChange()
}
if (oldSorting !== newSorting) {
onSortChange && onSortChange()
}
if (appendData && (oldFilters !== newFilters || oldSorting !== newSorting)) {
resetAppend()
}
oldApiProps.current = { ...stdApiProp }
})Gestione automatica sistema e lingua
Al cambio del sistema o della lingua viene eseguita una nuova chiamata in automatico\
useEffect(() => {
if (refreshOnAuthContextChangeHookFirstRunCompleted.current) {
internalRefresh()
}
refreshOnAuthContextChangeHookFirstRunCompleted.current = true
}, [systemId, languageStore.activeLanguageKey])Refresh al cambio dipendenze e primo render
Al cambio di una dipendenza se refreshOnDepChange = true allora viene eseguita una nuova chiamata
Al primo render se fetchOnFirstRender = true allora viene eseguita una chiamata
Se enableDebounce = true allora le chiamate al cambio dipendenze dopo il primo rendere vengono eseguite in debounce
La chiamata al primo render è sempre senza debounce.
useEffect(() => {
cancel() //cancel debounce al primo render, altrimenti parte una chiamata in automatico non voluta
if (refreshOnDepChange && refreshHookFirstRunCompleted.current) {
if (enableDebounce) {
internalRefreshDebounce()
} else {
internalRefresh()
}
}
if (fetchOnFirstRender && !refreshHookFirstRunCompleted.current) {
internalRefresh()
}
refreshHookFirstRunCompleted.current = true
}, dependencies)Funzione reset append
const resetAppend = () => {
dataRef.current = []
}Chiamata API
Questa funzione si occupa di gestire stato di loading e refresh della chiamata API.
Inoltre se è abilitato append dei dati nel buffer aggiunge ogni singolo chunk nel buffer controllando eventuali duplicati tramite id.
Le dipendenze della funzione non causano un auto-fetch ma servono solo ad ottenere i nuovi parametri aggiornati da dare alla Standard API.
Nel caso in cui la risposta dell’ API sia con responseCode !== da 200 mostra un toast con il messaggio d’errore impostato.
Infine injecta nel JSON delle API systemId e activeLanguageKey recuperate dallo store.\
const [{ loading, value }, refresh] = useAsyncFn(async () => {
// clono oggetto per non modificare la source in entrata
const _props = JSON.parse(JSON.stringify(stdApiProp))
_props.systemId = systemId
_props.activeLanguageKey = languageStore.activeLanguageKey
const api = new StdApi<BASE_OBJ, RESPONSE_OBJ, INCLUDED_BASE_OBJ, INCLUDED_RES_OBJ>(_props)
const getResponse = await api.get()
if (api.lastQuery.responseCode !== 200) {
notifyError(errorMessage)
return {}
}
const zipResponse = api.zipResponse()
if (appendData) {
if (dataRef.current.length > 0) {
dataRef.current = merge(dataRef.current, zipResponse, (a, b) => a.key === b.key)
} else {
dataRef.current = [...zipResponse]
}
}
return {
data: getResponse,
zipResponse: zipResponse,
lastQuery: api.lastQuery,
responseCode: api.lastQuery.responseCode,
appendedZipResponse: dataRef.current,
postProcessedData: postProcess ? postProcess(zipResponse) : undefined
} as ApiResponse<RESPONSE_OBJ, INCLUDED_RES_OBJ>
}, [JSON.stringify(stdApiProp), systemId, languageStore.activeLanguageKey])Valori di ritorno
return {
value: value ?? {},
loading,
refresh: internalRefresh,
refreshDebounce: internalRefreshDebounce,
cancelDebounce: cancel,
isReadyDebounce: isReady,
resetAppend
} as unknown as useStandardApiV2ReturnType<RESPONSE_OBJ, INCLUDED_RES_OBJ>