Nel mondo Vue (v3+), i design pattern non sono identici a quelli dei linguaggi orientati agli oggetti (come Java o C#), ma esistono pattern ricorrenti che aiutano a strutturare, riutilizzare e mantenere facilmente il codice nelle applicazioni complesse.
Ecco la lista dei design pattern più usati in Vue 3, con una breve spiegazione di ciascuno:
-
Scopo: Separare la logica di business dalla UI.
-
Descrizione:
- Container Component: gestisce stato, chiamate API, logica.
- Presentational Component: mostra i dati, riceve solo
props.
-
Alternativa moderna: logica nei composables (
useSomething()) e componenti “dumb” per la sola UI.
-
Scopo: Incapsulare e riutilizzare logica reattiva tra componenti.
-
Descrizione: Funzioni che usano la Composition API (
ref,computed,watch, ecc.) e ritornano dati/metodi condivisibili. -
Esempio:
// useFetch.js import { ref, onMounted } from 'vue' export function useFetch(url) { const data = ref(null) const error = ref(null) onMounted(async () => { try { const res = await fetch(url) data.value = await res.json() } catch (e) { error.value = e } }) return { data, error } }
- Scopo: Condividere stato o funzioni tra componenti senza prop drilling.
- Descrizione: Un componente parent usa
provide()per esporre valori, i discendenti li leggono coninject(). - Esempio tipico: Temi, autenticazione, configurazioni globali.
-
Scopo: Passare contenuti dinamici e flessibili ai componenti figli.
-
Descrizione:
- Slot normali → sostituiscono contenuto.
- Scoped slots → passano dati o metodi dal figlio al contenuto del genitore.
-
Esempio:
<List :items="users" v-slot="{ item }"> <UserCard :user="item" /> </List>
-
Scopo: Gestire stato condiviso e complesso in modo scalabile.
-
Descrizione:
- Usa Pinia o Vuex come store globale.
- Incapsula mutazioni, azioni e getter.
-
Alternativa leggera:
reactive()+provide/inject.
-
Scopo: Generare composables configurabili.
-
Esempio:
export function createApiComposable(baseUrl) { return function useApi(endpoint) { const data = ref(null) async function fetchData() { const res = await fetch(`${baseUrl}${endpoint}`) data.value = await res.json() } return { data, fetchData } } } const useUserApi = createApiComposable('/api/users')
-
Scopo: Costruire componenti flessibili e componibili.
-
Descrizione: Un componente principale espone sottocomponenti interni che condividono lo stesso contesto.
-
Esempio:
<Tabs> <TabsList> <Tab>Uno</Tab> <Tab>Due</Tab> </TabsList> <TabPanels> <TabPanel>Contenuto 1</TabPanel> <TabPanel>Contenuto 2</TabPanel> </TabPanels> </Tabs>
-
Implementazione tipica:
provide/injectper condividere stato tra le parti.
-
Scopo: Avvolgere l’app con fornitori di stato o servizi (tema, auth, store).
-
Esempio:
<ThemeProvider> <App /> </ThemeProvider>
Con
ThemeProviderche usaprovide('theme', themeValue).
- Scopo: Gestire input e stato dei form.
- Controlled: valore gestito da
v-model. - Uncontrolled: valore gestito nativamente (via
ref), utile per performance o compatibilità con librerie esterne.
-
Scopo: Passare comportamento come props o funzioni.
-
Descrizione: Vue consente di passare funzioni personalizzate per gestire strategie o logiche diverse.
-
Esempio:
<Button :onClick="customLogic" />
Oppure con
render()function per massima flessibilità.
- Scopo: Gestire stato complesso in modo modulare.
- Descrizione: Usa
reactive()oref()per creare oggetti reattivi e passarli ad altri componenti o composables.
- ✅ Composables (Composition API Pattern)
- ✅ Provide/Inject Pattern
- ✅ Compound Components Pattern
- ✅ Composable Factory Pattern
- ✅ Global Provider / State Management Pattern
👉 Spiegazione completa dei pattern disponibili al repo: 📘 https://github.com/DavideNas/Design-Patterns-and-Angular (link originale di riferimento)