🎉 T-wiki 1.3.0 is released

FRONT-ENDHooksuseStandardApiV2

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 stdApiProp varia
  • onSortChange: come onFiltersChange ma 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>