Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Composables w produkcji

Ostatni etap przed wdrozeniem systemow NOVA LAB na Marsie - poznajmy sprawdzone wzorce stosowane w produkcyjnych aplikacjach Vue 3.

Organizacja plikow composables

W duzych projektach kluczowa jest czytelna struktura plikow.

1src/
2  composables/
3    useAuth.ts         # Autoryzacja
4    useNotifications.ts # Powiadomienia
5    useSensors.ts      # Dane sensorow
6    useTheme.ts        # Motyw aplikacji
7    index.ts           # Re-export wszystkich composables
1// composables/index.ts - centralny punkt eksportu
2export { useAuth } from './useAuth'
3export { useNotifications } from './useNotifications'
4export { useSensors } from './useSensors'
5export { useTheme } from './useTheme'
6
7// Import w komponencie - czysty i czytelny
8import { useAuth, useNotifications } from '@/composables'

Typowanie composables z TypeScript

TypeScript zapewnia bezpieczenstwo typow i lepsze podpowiedzi IDE.

1import { ref, computed, Ref, ComputedRef } from 'vue'
2
3// Interfejs dla zwracanego API
4interface UsePaginationReturn {
5  currentPage: Ref<number>
6  totalPages: ComputedRef<number>
7  paginatedItems: ComputedRef<any[]>
8  goToPage: (page: number) => void
9  nextPage: () => void
10  prevPage: () => void
11}
12
13// Typowany composable
14function usePagination<T>(
15  items: Ref<T[]>,
16  perPage: number = 10
17): UsePaginationReturn {
18  const currentPage = ref(1)
19
20  const totalPages = computed(() =>
21    Math.ceil(items.value.length / perPage)
22  )
23
24  const paginatedItems = computed(() => {
25    const start = (currentPage.value - 1) * perPage
26    return items.value.slice(start, start + perPage)
27  })
28
29  function goToPage(page: number) {
30    if (page >= 1 && page <= totalPages.value) {
31      currentPage.value = page
32    }
33  }
34
35  function nextPage() { goToPage(currentPage.value + 1) }
36  function prevPage() { goToPage(currentPage.value - 1) }
37
38  return {
39    currentPage,
40    totalPages,
41    paginatedItems,
42    goToPage,
43    nextPage,
44    prevPage
45  }
46}

Composable z opcjami konfiguracyjnymi

Wzorzec opcji pozwala na elastyczna konfiguracje composable - jak panele konfiguracyjne modulow NOVA LAB.

1import { ref, watch, onUnmounted } from 'vue'
2
3interface UsePollingOptions {
4  interval?: number
5  immediate?: boolean
6  retryOnError?: boolean
7  maxRetries?: number
8  onError?: (error: Error) => void
9}
10
11function usePolling(
12  fetchFn: () => Promise<any>,
13  options: UsePollingOptions = {}
14) {
15  const {
16    interval = 5000,
17    immediate = true,
18    retryOnError = true,
19    maxRetries = 3,
20    onError
21  } = options
22
23  const data = ref(null)
24  const error = ref(null)
25  const isPolling = ref(false)
26  const retryCount = ref(0)
27  let timerId: number | null = null
28
29  async function poll() {
30    try {
31      data.value = await fetchFn()
32      error.value = null
33      retryCount.value = 0
34    } catch (e) {
35      error.value = e
36      onError?.(e)
37
38      if (!retryOnError || retryCount.value >= maxRetries) {
39        stopPolling()
40        return
41      }
42      retryCount.value++
43    }
44  }
45
46  function startPolling() {
47    if (isPolling.value) return
48    isPolling.value = true
49    if (immediate) poll()
50    timerId = setInterval(poll, interval)
51  }
52
53  function stopPolling() {
54    isPolling.value = false
55    if (timerId) {
56      clearInterval(timerId)
57      timerId = null
58    }
59  }
60
61  onUnmounted(stopPolling)
62
63  return { data, error, isPolling, retryCount, startPolling, stopPolling }
64}
65
66// Uzycie z opcjami
67const sensorData = usePolling(
68  () => fetch('/api/sensors').then(r => r.json()),
69  {
70    interval: 3000,
71    immediate: true,
72    maxRetries: 5,
73    onError: (e) => console.error('Polling failed:', e)
74  }
75)

Composable z provide/inject dla duzych aplikacji

W produkcyjnych aplikacjach czesto potrzebujemy wspoldzielonego stanu bez prop drilling.

1import { ref, computed, provide, inject, readonly } from 'vue'
2
3const StoreKey = Symbol('AppStore')
4
5// Tworzymy raz w komponencie glownym (App.vue)
6function createAppStore() {
7  const user = ref(null)
8  const isAuthenticated = computed(() => user.value !== null)
9  const notifications = ref([])
10
11  function login(userData) { user.value = userData }
12  function logout() { user.value = null }
13  function notify(message, type = 'info') {
14    notifications.value.push({
15      id: Date.now(),
16      message,
17      type,
18      timestamp: new Date()
19    })
20  }
21
22  const store = {
23    user: readonly(user),
24    isAuthenticated,
25    notifications: readonly(notifications),
26    login,
27    logout,
28    notify
29  }
30
31  provide(StoreKey, store)
32  return store
33}
34
35// Uzywamy w dowolnym zagniezdonym komponencie
36function useAppStore() {
37  const store = inject(StoreKey)
38  if (!store) {
39    throw new Error('useAppStore wymaga createAppStore w App.vue')
40  }
41  return store
42}

Podsumowanie modulu

W tym module poznales zaawansowane techniki pracy z composables:

  • Factory composables - tworzenie wielu instancji composable z rozna konfiguracją
  • Kompozycja - laczenie composables w wieksze systemy, composable uzywajacy innego composable
  • Dependency Injection -
    provide/inject
    dla wspoldzielonego stanu bez prop drilling
  • Reaktywne wzorce - Singleton, Event Bus, State Machine, Observer - wszystkie z reaktywnoscia Vue
  • VueUse - 200+ gotowych composables (
    useLocalStorage
    ,
    useDark
    ,
    useWindowSize
    )
  • Testowanie - unit testy composables z Vitest, mockowanie, testowanie asynchronicznych operacji
  • Optymalizacja -
    shallowRef
    dla duzych danych, computed caching, unikanie wyciekow pamieci
  • Produkcja - TypeScript typowanie, organizacja plikow, wzorzec opcji konfiguracyjnych

Te techniki pozwola Ci budowac skalowalne i wydajne aplikacje Vue 3 - gotowe na misje kosmiczne!

Vai a CodeWorlds