Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Performance i optymalizacja Composables

W stacji NOVA LAB kazdy wat energii sie liczy - tak samo w aplikacjach Vue kazdy niepotrzebny render i obliczenie to strata wydajnosci. Poznajmy techniki optymalizacji composables.

shallowRef - plytka reaktywnosc

ref()
tworzy gleboka reaktywnosc - kazda zmiana wewnatrz obiektu powoduje aktualizacje.
shallowRef()
reaguje tylko na zmiane calej wartosci, nie wewnetrznych wlasciwosci.

1import { shallowRef, triggerRef } from 'vue'
2
3// Duza lista danych - shallowRef jest wydajniejszy
4const sensorReadings = shallowRef([])
5
6// To NIE wywoła aktualizacji (plytka reaktywnosc)
7sensorReadings.value.push({ id: 1, temp: 22 })
8
9// To wywoła aktualizacje - przypisanie nowej tablicy
10sensorReadings.value = [...sensorReadings.value, { id: 1, temp: 22 }]
11
12// Alternatywnie: reczne wyzwolenie aktualizacji
13sensorReadings.value.push({ id: 2, temp: 23 })
14triggerRef(sensorReadings) // Wymus aktualizacje
1<script setup>
2import { shallowRef, triggerRef, computed } from 'vue'
3
4// Wydajny composable dla duzych zbiorow danych
5function useLargeDataset() {
6  const items = shallowRef([])
7  const count = computed(() => items.value.length)
8
9  function addItem(item) {
10    // Tworzymy nowa tablice - wyzwala reaktywnosc
11    items.value = [...items.value, item]
12  }
13
14  function addMany(newItems) {
15    // Jedna aktualizacja zamiast N
16    items.value = [...items.value, ...newItems]
17  }
18
19  function removeItem(id) {
20    items.value = items.value.filter(item => item.id !== id)
21  }
22
23  function updateItem(id, updates) {
24    items.value = items.value.map(item =>
25      item.id === id ? { ...item, ...updates } : item
26    )
27  }
28
29  return { items, count, addItem, addMany, removeItem, updateItem }
30}
31</script>

Kiedy uzywac

shallowRef
:

  • Duze tablice (100+ elementow)
  • Obiekty z wieloma zagniezdzeniami
  • Dane, ktore zmieniasz rzadko lub calosciowo

Computed caching

Computed properties sa automatycznie cachowane - przeliczaja sie tylko gdy zmienia sie ich zaleznosc. To kluczowa optymalizacja.

1import { ref, computed } from 'vue'
2
3function useFilteredExperiments() {
4  const experiments = ref([])
5  const searchQuery = ref('')
6  const category = ref('all')
7
8  // DOBRZE: computed jest cachowane
9  // Przelicza sie TYLKO gdy experiments, searchQuery lub category sie zmienia
10  const filtered = computed(() => {
11    console.log('Przeliczam filtrowane eksperymenty') // loguje rzadko
12    let result = experiments.value
13
14    if (searchQuery.value) {
15      const q = searchQuery.value.toLowerCase()
16      result = result.filter(e =>
17        e.name.toLowerCase().includes(q)
18      )
19    }
20
21    if (category.value !== 'all') {
22      result = result.filter(e => e.category === category.value)
23    }
24
25    return result
26  })
27
28  // ZLE: funkcja przelicza za kazdym renderem
29  function getFiltered() {
30    console.log('Przeliczam za kazdym razem!') // loguje czesto
31    return experiments.value.filter(...)
32  }
33
34  // DOBRZE: laczenie computed w lancuch
35  const stats = computed(() => ({
36    total: filtered.value.length,
37    active: filtered.value.filter(e => e.status === 'active').length,
38    completed: filtered.value.filter(e => e.status === 'completed').length
39  }))
40
41  return { experiments, searchQuery, category, filtered, stats }
42}

watchEffect vs watch - wydajnosc

watch
i
watchEffect
roznia sie nie tylko API, ale tez wydajnoscia.

1import { ref, watch, watchEffect } from 'vue'
2
3const temperature = ref(22)
4const pressure = ref(101)
5const humidity = ref(45)
6
7// watchEffect - sledzi WSZYSTKIE uzyyte reaktywne wartosci
8// Odpala sie przy zmianie temperature, pressure LUB humidity
9watchEffect(() => {
10  console.log('watchEffect:', temperature.value)
11  // Nawet jesli uzywasz pressure tylko w warunku,
12  // watchEffect sledzi je ZAWSZE
13  if (temperature.value > 30) {
14    console.log('Cisnienie:', pressure.value)
15  }
16})
17
18// watch - sledzi TYLKO okreslone zrodlo
19// Odpala sie TYLKO przy zmianie temperature
20watch(temperature, (newTemp) => {
21  console.log('watch:', newTemp)
22  // Mozesz czytac inne refs bez tworzenia zaleznosci
23  if (newTemp > 30) {
24    console.log('Cisnienie:', pressure.value)
25  }
26})

Reguła: uzywaj

watch
gdy potrzebujesz reagowac na konkretne zmiany. Uzywaj
watchEffect
gdy chcesz automatycznego sledzenia wielu zaleznosci.

Wycieki pamieci w Composables

Jeden z najczestszych problemow - niesprzątnięte zasoby powoduja wycieki pamieci.

1import { ref, onMounted, onUnmounted, watch } from 'vue'
2
3// ZLE - wyciek pamieci!
4function useLeakyTimer() {
5  const seconds = ref(0)
6
7  onMounted(() => {
8    setInterval(() => { // Nigdy nie czyścimy!
9      seconds.value++
10    }, 1000)
11  })
12
13  return { seconds }
14}
15
16// DOBRZE - poprawny cleanup
17function useSafeTimer() {
18  const seconds = ref(0)
19  const isRunning = ref(false)
20  let intervalId = null
21
22  function start() {
23    if (isRunning.value) return
24    isRunning.value = true
25    intervalId = setInterval(() => {
26      seconds.value++
27    }, 1000)
28  }
29
30  function stop() {
31    if (!isRunning.value) return
32    isRunning.value = false
33    clearInterval(intervalId)
34    intervalId = null
35  }
36
37  // Zawsze czyscimy w onUnmounted
38  onUnmounted(() => {
39    if (intervalId) {
40      clearInterval(intervalId)
41    }
42  })
43
44  return { seconds, isRunning, start, stop }
45}

Checklist wydajnosci composables

| Technika | Kiedy uzywac | |----------|-------------| |

shallowRef
| Duze tablice/obiekty, rzadkie aktualizacje | |
computed
zamiast funkcji | Wartosc zalezy od reactive state | |
watch
zamiast
watchEffect
| Konkretne zrodlo do obserwacji | | Cleanup w
onUnmounted
| Timery, event listeners, WebSocket | | Batch updates | Wiele zmian naraz zamiast po jednej | |
triggerRef
| Mutacja shallowRef bez tworzenia kopii |

1// Batch updates - jedna aktualizacja zamiast trzech
2import { ref } from 'vue'
3
4function useBatchUpdate() {
5  const data = ref({ temp: 0, pressure: 0, humidity: 0 })
6
7  // ZLE: 3 oddzielne aktualizacje
8  function updateBad(temp, pressure, humidity) {
9    data.value.temp = temp       // render
10    data.value.pressure = pressure // render
11    data.value.humidity = humidity // render
12  }
13
14  // DOBRZE: 1 aktualizacja (nowy obiekt)
15  function updateGood(temp, pressure, humidity) {
16    data.value = { temp, pressure, humidity } // 1 render
17  }
18
19  return { data, updateGood }
20}
Przejdź do CodeWorlds