useRemoteFetch
Panoramica
useRemoteFetch gestisce il fetch di dati per tutti i componenti "remote" di @pzeta/vue-form (es. SelectRemote, ListboxRemote, TreeRemote). Fornisce:
- Filtri statici applicati a tutte le richieste
- Filtri dinamici che si aggiornano automaticamente al cambiamento di altri campi del form
- Prevenzione race condition tramite request ID e
AbortController - Loading state e gestione errori reattivi
- Varianti integrate:
useRemoteFetchPostgRESTper PostgREST,useRemoteSetupper componenti
API
import { useRemoteFetch } from '@pzeta/vue-form'
export function useRemoteFetch<T = Record<string, unknown>>(
options: UseRemoteFetchOptions<T> | Ref<UseRemoteFetchOptions<T>>,
): UseRemoteFetchReturn<T>
Tipi
export interface UseRemoteFetchOptions<T = Record<string, unknown>> {
fetchFn?: (filters?: FilterCriteria, signal?: AbortSignal) => Promise<T[]>
filter?: string | FilterCriteria
filterFields?: string[]
fullData?: Record<string, unknown>
immediate?: boolean // default: true
componentName?: string
onError?: (error: Error, componentName: string) => void
}
export interface UseRemoteFetchReturn<T = Record<string, unknown>> {
data: Ref<T[]>
loading: Ref<boolean>
error: Ref<Error | null>
combinedFilters: ComputedRef<FilterCriteria | undefined>
reload: () => Promise<void>
setData: (newData: T[]) => void
}
Parametri / Opzioni
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
fetchFn | FetchFn<T> | — | Funzione async che riceve i filtri combinati e ritorna T[] |
filter | string | FilterCriteria | — | Filtro statico applicato a tutte le richieste. Stringa JSON o oggetto |
filterFields | string[] | — | Campi del form da osservare per filtri dinamici |
fullData | Record<string, unknown> | — | Oggetto con tutti i valori del form (sorgente dei filtri dinamici) |
immediate | boolean | true | Se false, il caricamento non parte al mount |
componentName | string | 'useRemoteFetch' | Nome usato nei messaggi di errore/log |
onError | (error, name) => void | — | Callback per gestione errori personalizzata |
Le opzioni possono essere passate come oggetto statico oppure come Ref<UseRemoteFetchOptions<T>>. Nel secondo caso, qualsiasi cambiamento alle opzioni provoca un nuovo fetch.
Valore di ritorno
| Proprietà | Tipo | Descrizione |
|---|---|---|
data | Ref<T[]> | Array reattivo con i dati caricati. Vuoto finché il fetch non completa |
loading | Ref<boolean> | true durante il fetch |
error | Ref<Error | null> | Errore dell'ultimo fetch, null se nessun errore |
combinedFilters | ComputedRef<FilterCriteria | undefined> | Filtri effettivamente applicati (statici + dinamici) |
reload | () => Promise<void> | Esegue un nuovo fetch con i filtri correnti |
setData | (newData: T[]) => void | Imposta i dati senza eseguire fetch |
Esempi
Uso base con filtro statico
import { useRemoteFetch } from '@pzeta/vue-form'
const { data: utenti, loading, error } = useRemoteFetch({
fetchFn: (filters) => api.getUtenti(filters),
filter: { attivo: true },
immediate: true,
componentName: 'UtenteSelect',
})
<template>
<div v-if="loading">Caricamento...</div>
<div v-else-if="error" class="text-red-500">{{ error.message }}</div>
<SelectRemote v-else :options="utenti" />
</template>
Filtri dinamici da altri campi del form
Quando formData.provinciaId cambia, comuni vengono ricaricati automaticamente con il nuovo filtro.
const formData = ref({ provinciaId: null as number | null, comuneId: null })
const { data: comuni, loading } = useRemoteFetch({
fetchFn: (filters) => api.getComuni(filters),
filterFields: ['provinciaId'], // osserva questo campo
fullData: formData.value, // sorgente dei valori
componentName: 'ComuneSelect',
})
I filtri dinamici vengono combinati con operatore eq. Il computed combinedFilters rifletterà:
{ "provinciaId": { "operator": "eq", "value": 3 } }
Caricamento lazy (immediate: false)
const { data, loading, reload } = useRemoteFetch({
fetchFn: fetchCategorie,
immediate: false,
componentName: 'CategoriaSelect',
})
// Carica solo all'apertura del dropdown
const onDropdownOpen = async () => {
if (data.value.length === 0) {
await reload()
}
}
Gestione errori con callback
const { data, error, reload } = useRemoteFetch({
fetchFn: fetchDati,
componentName: 'DatiRemoti',
onError: (err, name) => {
toast.error(`[${name}] ${err.message}`)
logger.error(err)
},
})
Opzioni reattive (Ref)
Quando si vuole cambiare il filtro statico dopo l'inizializzazione:
const options = ref({
fetchFn: fetchArticoli,
filter: { categoria: 'A' } as FilterCriteria,
})
const { data } = useRemoteFetch(options)
// Cambia categoria — trigger automatico del reload
const onCategoriaChange = (nuovaCategoria: string) => {
options.value = { ...options.value, filter: { categoria: nuovaCategoria } }
}
Impostare i dati manualmente
const { data, setData } = useRemoteFetch({ fetchFn: fetchOpzioni })
// Pre-popola con dati di default
setData([{ id: 0, label: '-- Nessuno --' }])
// Aggiorna dopo una creazione locale senza ri-fetchare
const onNuovoRecord = (nuovoRecord: Opzione) => {
setData([...data.value, nuovoRecord])
}
Varianti
useRemoteFetchPostgREST
Wrapper che integra useRemoteFetch con repository @pzeta/postgrest. Gestisce automaticamente cache, schema e deduplication.
import { useRemoteFetchPostgREST } from '@pzeta/vue-form'
const { data: cities, loading } = useRemoteFetchPostgREST<City>({
path: '/cities',
keyName: 'idcity',
filterFields: ['idprovincia'],
fullData: formData.value,
repositoryOptions: {
useCache: true,
cacheTTL: 1800000, // 30 minuti (default)
},
})
| Opzione aggiuntiva | Tipo | Default | Descrizione |
|---|---|---|---|
path | string | — | Path endpoint PostgREST (es. '/cities') |
keyName | keyof T | — | Nome della chiave primaria |
schema | string | — | Schema PostgreSQL (override globale) |
repositoryOptions.useCache | boolean | true | Abilita cache risultati |
repositoryOptions.cacheTTL | number | 1800000 | TTL cache in ms (default 30 min) |
repositoryOptions.isAuthRequired | boolean | true | Richiede autenticazione |
useRemoteSetup
Composable di supporto interno usato dai componenti remote per centralizzare il boilerplate di setup. Accetta le props del componente e un nome, restituisce l'output di useRemoteFetch.
import { useRemoteSetup } from '@pzeta/vue-form'
// Dentro un componente remote custom
const props = defineProps<MyRemoteProps>()
const { data, loading, error, reload } = useRemoteSetup(props, 'MyRemote', {
immediate: false,
})
Note
- I filtri dinamici escludono automaticamente valori
null,undefinede stringhe vuote. - Le race condition sono gestite internamente tramite request ID e
AbortController: le risposte stale vengono silenziosamente ignorate. - Il watch sui filtri dinamici è ottimizzato: osserva solo i campi specificati in
filterFieldstramite computed, non esegue deep watch su tuttofullData.
useOptionLabel
Composable per risolvere la label di un'opzione da un oggetto con supporto a campo singolo, template ${campo} e dot-notation per campi annidati.
useRemoteSetup
Wrapper di useRemoteFetch che estrae automaticamente fetchFn, filter, filterFields e fullData dalle props di un componente. Centralizza il boilerplate dei wrapper *Remote.