Kurs Vue.js · Moduł 11: Pinia

Getters w Pinia

2 min czytania
W tej lekcji4

Getters to wartości wyliczane na podstawie state - jak panele analityczne NOVA LAB, które przetwarzają surowe dane z czujników i prezentują je w czytelnej formie. Zmieniają się automatycznie gdy zmienia się state.

Podstawowe getters

W Composition API getters to zwykłe computed():

1import { defineStore } from 'pinia'
2import { ref, computed } from 'vue'
3
4export const useInventoryStore = defineStore('inventory', () => {
5  const items = ref([
6    { name: 'Oxygen Tank', quantity: 12, category: 'life-support' },
7    { name: 'Water Filter', quantity: 5, category: 'life-support' },
8    { name: 'Solar Panel', quantity: 8, category: 'energy' },
9    { name: 'Drill Bit', quantity: 20, category: 'mining' }
10  ])
11
12  // Prosty getter
13  const totalItems = computed(() =>
14    items.value.reduce((sum, item) => sum + item.quantity, 0)
15  )
16
17  // Getter filtrujący
18  const lifeSupportItems = computed(() =>
19    items.value.filter(item => item.category === 'life-support')
20  )
21
22  // Getter sprawdzający warunek
23  const hasShortage = computed(() =>
24    items.value.some(item => item.quantity < 3)
25  )
26
27  return { items, totalItems, lifeSupportItems, hasShortage }
28})

Getters używające innych getters

Getters mogą bazować na innych getters:

1const lowStockItems = computed(() =>
2  items.value.filter(item => item.quantity < 5)
3)
4
5const lowStockCount = computed(() => lowStockItems.value.length)
6
7const stockStatus = computed(() => {
8  if (lowStockCount.value === 0) return 'OK'
9  if (lowStockCount.value <= 2) return 'WARNING'
10  return 'CRITICAL'
11})

Getters z parametrami

Computed nie przyjmuje argumentów, ale możesz zwrócić funkcję:

1// Getter z parametrem - zwraca funkcję
2const getItemsByCategory = computed(() => {
3  return (category) =>
4    items.value.filter(item => item.category === category)
5})
6
7const findItem = computed(() => {
8  return (name) =>
9    items.value.find(item =>
10      item.name.toLowerCase().includes(name.toLowerCase())
11    )
12})

Użycie w komponencie:

1<template>
2  <div>
3    <p>Total: {{ store.totalItems }}</p>
4    <p>Status: {{ store.stockStatus }}</p>
5
6    <!-- Getter z parametrem -->
7    <div v-for="item in store.getItemsByCategory('energy')" :key="item.name">
8      {{ item.name }}: {{ item.quantity }}
9    </div>
10  </div>
11</template>

Getters w storeToRefs

Getters (computed) są częścią storeToRefs:

1<script setup>
2import { storeToRefs } from 'pinia'
3import { useInventoryStore } from '@/stores/inventory'
4
5const store = useInventoryStore()
6const { items, totalItems, hasShortage } = storeToRefs(store)
7</script>
Kod do tej lekcji: App.vue
1<script setup>
2import { ref, computed } from 'vue'
3
4// Symulacja store magazynu z getterami
5const items = ref([
6  { name: 'Butla z tlenem', quantity: 12, category: 'life-support', unit: 'szt.' },
7  { name: 'Filtr wody', quantity: 2, category: 'life-support', unit: 'szt.' },
8  { name: 'Panel słoneczny', quantity: 8, category: 'energy', unit: 'szt.' },
9  { name: 'Akumulator', quantity: 15, category: 'energy', unit: 'szt.' },
10  { name: 'Wiertło', quantity: 20, category: 'mining', unit: 'szt.' },
11  { name: 'Pojemnik na próbki skał', quantity: 1, category: 'mining', unit: 'szt.' }
12])
13
14const searchQuery = ref('')
15const selectedCategory = ref('all')
16
17// Getters
18const totalItems = computed(() =>
19  items.value.reduce((sum, item) => sum + item.quantity, 0)
20)
21
22const categories = computed(() =>
23  ['all', ...new Set(items.value.map(i => i.category))]
24)
25
26const filteredItems = computed(() => {
27  let result = items.value
28  if (selectedCategory.value !== 'all') {
29    result = result.filter(i => i.category === selectedCategory.value)
30  }
31  if (searchQuery.value) {
32    const q = searchQuery.value.toLowerCase()
33    result = result.filter(i => i.name.toLowerCase().includes(q))
34  }
35  return result
36})
37
38const lowStockItems = computed(() =>
39  items.value.filter(item => item.quantity < 5)
40)
41
42const stockStatus = computed(() => {
43  if (lowStockItems.value.length === 0) return 'OK'
44  if (lowStockItems.value.length <= 2) return 'WARNING'
45  return 'CRITICAL'
46})
47
48// Getter z parametrem
49const getByCategory = computed(() => {
50  return (cat) => items.value.filter(i => i.category === cat)
51})
52</script>
53
54<template>
55  <div class="nova-lab">
56    <h1>NOVA LAB - gettery magazynu</h1>
57
58    <div class="stats-bar">
59      <div class="stat-card">
60        <div class="stat-value">{{ totalItems }}</div>
61        <div class="stat-label">Sztuk łącznie</div>
62      </div>
63      <div class="stat-card">
64        <div class="stat-value" :class="stockStatus.toLowerCase()">{{ stockStatus }}</div>
65        <div class="stat-label">Stan magazynu</div>
66      </div>
67      <div class="stat-card">
68        <div class="stat-value warning">{{ lowStockItems.length }}</div>
69        <div class="stat-label">Niski stan</div>
70      </div>
71    </div>
72
73    <div class="controls">
74      <input v-model="searchQuery" placeholder="Szukaj..." class="search-input" />
75      <select v-model="selectedCategory" class="select">
76        <option v-for="cat in categories" :key="cat" :value="cat">
77          {{ cat === 'all' ? 'Wszystkie kategorie' : cat }}
78        </option>
79      </select>
80    </div>
81
82    <div class="inventory-grid">
83      <div v-for="item in filteredItems" :key="item.name"
84        class="item-card" :class="{ 'low-stock': item.quantity < 5 }">
85        <div class="item-name">{{ item.name }}</div>
86        <div class="item-qty">{{ item.quantity }} {{ item.unit }}</div>
87        <div class="item-cat">{{ item.category }}</div>
88      </div>
89    </div>
90
91    <div v-if="lowStockItems.length" class="alert-box">
92      Niski stan: {{ lowStockItems.map(i => i.name).join(', ') }}
93    </div>
94  </div>
95</template>
96
97<style scoped>
98.nova-lab {
99  background: #0a0e27;
100  color: #00ff88;
101  min-height: 100vh;
102  padding: 20px;
103  font-family: monospace;
104}
105h1 { color: #00ff88; margin-bottom: 20px; text-align: center; }
106.stats-bar { display: flex; gap: 10px; margin-bottom: 15px; justify-content: center; }
107.stat-card {
108  background: rgba(0, 180, 216, 0.1);
109  border: 2px solid #00b4d8;
110  padding: 12px 20px;
111  text-align: center;
112}
113.stat-value { font-size: 1.4em; font-weight: bold; }
114.stat-label { color: #00b4d8; font-size: 0.8em; margin-top: 4px; }
115.ok { color: #00ff88; }
116.warning { color: #ff9900; }
117.critical { color: #ff4444; }
118.controls { display: flex; gap: 10px; margin-bottom: 15px; max-width: 500px; margin: 0 auto 15px; }
119.search-input, .select {
120  background: #0a0e27;
121  border: 2px solid #00b4d8;
122  color: #00ff88;
123  padding: 8px;
124  font-family: monospace;
125  flex: 1;
126}
127.inventory-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
128.item-card {
129  background: rgba(0, 255, 136, 0.05);
130  border: 2px solid #00ff88;
131  padding: 12px;
132}
133.item-card.low-stock { border-color: #ff4444; background: rgba(255, 68, 68, 0.1); }
134.item-name { font-weight: bold; margin-bottom: 5px; }
135.item-qty { color: #00b4d8; }
136.item-cat { color: #666; font-size: 0.85em; margin-top: 4px; }
137.alert-box {
138  margin-top: 15px;
139  padding: 10px;
140  background: rgba(255, 68, 68, 0.1);
141  border: 2px solid #ff4444;
142  color: #ff4444;
143}
144</style>

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Czym są getters w Pinia (Composition API)?

  2. 2. Jak zdefiniować getter w Composition API style?

To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Edytor kodu

    Stwórz gettery: totalItems, hasShortage i stockStatus.

  • Układanie w poziomie

    Ułóż definicję gettera computed w store:

  • Klikanie w kolejności

    Ułóż getter z parametrem (zwracający funkcję):

  • Edytor kodu

    Zdefiniuj lifeSupportItems (filtrujący) i getItemsByCategory (parametryczny getter).

Przydatne artykuły