Composables

useRemoteSetup

Wrapper di useRemoteFetch che estrae automaticamente fetchFn, filter, filterFields e fullData dalle props di un componente. Centralizza il boilerplate dei wrapper *Remote.

Panoramica

useRemoteSetup è il composable interno usato da tutti i wrapper *Remote di @pzeta/vue-form (SelectRemote, ListboxRemote, TreeRemote, RadioGroupRemoteInput, InplaceSelectRemote, OrderListRemote, PickListRemote). Riceve direttamente le props del componente e ne estrae le quattro chiavi standard (fetchFn, filter, filterFields, fullData) costruendo una computed<UseRemoteFetchOptions> reattiva, poi invoca useRemoteFetch.

Se fetchFn non e fornita ma lo e endpoint, genera esso stesso la funzione di fetch componendo la chiamata PostgREST: risolve il trasporto durante il setup (dove inject() e utilizzabile) e carica i moduli PostgREST con import() alla prima richiesta. fetchFn ha sempre la precedenza. Vedi Sorgente dati endpoint.

In pratica: se stai scrivendo un wrapper custom in stile *Remote, usa useRemoteSetup invece di useRemoteFetch per ridurre il boilerplate. Se stai facendo un fetch puro non legato a props di componente, usa useRemoteFetch direttamente.

API

import { useRemoteSetup } from '@pzeta/vue-form'

export function useRemoteSetup<T = Record<string, unknown>>(
  props: RemoteSetupProps<T>,
  componentName: string,
  options?: RemoteSetupOptions,
): UseRemoteFetchReturn<T>

Tipi

export interface RemoteSetupProps<T = Record<string, unknown>> {
  fetchFn?: FetchFn<T>
  filter?: string | FilterCriteria
  filterFields?: RemoteFilterField[]
  fullData?: Record<string, unknown>
  /** Sorgente dati dichiarativa, usata solo se fetchFn non e fornita */
  endpoint?: string
  select?: string
  order?: string
  limit?: number
  baseUrl?: string
  keyName?: string
}

/** Forma breve (nome campo) o estesa (colonna + operatore) */
export type RemoteFilterField =
  | string
  | { field: string; column?: string; operator?: PostgrestOperator }

export interface RemoteSetupOptions {
  /** Se false, il fetch non parte al mount — chiamare reload() manualmente. Default: true */
  immediate?: boolean
}

Il return type è identico a quello di useRemoteFetch:

{
  data: Ref<T[]>
  loading: Ref<boolean>
  error: Ref<Error | null>
  combinedFilters: ComputedRef<FilterCriteria | undefined>
  reload: () => Promise<void>
  setData: (newData: T[]) => void
}

Parametri

ParametroTipoDescrizione
propsRemoteSetupProps<T>Oggetto props del componente — deve esporre almeno fetchFn, filter, filterFields, fullData (anche se opzionali), più le props della sorgente dichiarativa (endpoint, select, order, limit, baseUrl, keyName). Il composable osserva queste chiavi via Vue reactivity
componentNamestringNome del componente, usato per logging errori e tracing
optionsRemoteSetupOptions (opzionale)Opzioni aggiuntive — al momento solo immediate
Differenza con useRemoteFetch: useRemoteFetch riceve UseRemoteFetchOptions (o un Ref<UseRemoteFetchOptions>) costruito manualmente. useRemoteSetup costruisce quella computed per te dalle props del componente. È puro zucchero sintattico che elimina ~10 righe di boilerplate identico tra tutti i wrapper.

Esempi

Wrapper base

import { defineProps } from 'vue'
import { useRemoteSetup } from '@pzeta/vue-form'

interface MyRemoteSelectProps {
  fetchFn?: (filters?: Record<string, unknown>) => Promise<Array<Record<string, unknown>>>
  filter?: Record<string, unknown>
  filterFields?: string[]
  fullData?: Record<string, unknown>
  // ... altre props del componente
}

const props = defineProps<MyRemoteSelectProps>()

const { data, loading, error, reload } = useRemoteSetup(props, 'MyRemoteSelect')

Equivale a:

const fetchOptions = computed(() => ({
  fetchFn: props.fetchFn,
  filter: props.filter,
  componentName: 'MyRemoteSelect',
  ...(props.filterFields && { filterFields: props.filterFields }),
  ...(props.fullData && { fullData: props.fullData }),
}))

const { data, loading, error, reload } = useRemoteFetch(fetchOptions)

Lazy loading (immediate: false)

Per componenti che caricano solo quando l'utente li attiva (es. inplace edit, autocomplete on-focus):

const { data, loading, reload } = useRemoteSetup(props, 'MyInplaceSelect', {
  immediate: false,
})

const handleOpen = async () => {
  await reload()
}

Tipo generico

Per dataset non Record<string, unknown> (es. nodi albero):

import type { TreeNode } from '@pzeta/vue-form'

const { data: nodes, loading, reload } = useRemoteSetup<TreeNode>(props, 'MyTreeRemote')

Reattività e filtri dinamici

useRemoteSetup propaga interamente la reattività di useRemoteFetch:

  • Cambia props.filter → nuovo fetch automatico (debounced).
  • props.filterFields osserva chiavi specifiche di props.fullData → re-fetch quando uno di quei campi cambia (filtri a cascata, es. province dipende da regione).
  • combinedFilters espone i filtri finali mergiati (statici + dinamici) — utile per debug.

I dettagli su filtri statici/dinamici e prevenzione race condition sono in useRemoteFetch.

Quando NON usarlo

  • Fetch puri non legati a un componente: usa useRemoteFetch direttamente — non c'è alcun vantaggio nell'aggiungere lo strato.
  • Fetch a evento singolo (es. dentro un click handler): non serve un composable, basta una funzione async.

Vedi anche