Vue.js course Β· Module 11: Pinia
Getters in Pinia
In this lesson4
Getters are values computed based on state - like NOVA LAB analytical panels that process raw sensor data and present it in a readable form. They change automatically when the state changes.
Basic Getters
In Composition API, getters are simply 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 // Simple getter
13 const totalItems = computed(() =>
14 items.value.reduce((sum, item) => sum + item.quantity, 0)
15 )
16
17 // Filtering getter
18 const lifeSupportItems = computed(() =>
19 items.value.filter(item => item.category === 'life-support')
20 )
21
22 // Condition-checking getter
23 const hasShortage = computed(() =>
24 items.value.some(item => item.quantity < 3)
25 )
26
27 return { items, totalItems, lifeSupportItems, hasShortage }
28})Getters Using Other Getters
Getters can be based on other 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 with Parameters
Computed doesn't accept arguments, but you can return a function:
1// Getter with parameter - returns a function
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})Usage in a component:
1<template>
2 <div>
3 <p>Total: {{ store.totalItems }}</p>
4 <p>Status: {{ store.stockStatus }}</p>
5
6 <!-- Getter with parameter -->
7 <div v-for="item in store.getItemsByCategory('energy')" :key="item.name">
8 {{ item.name }}: {{ item.quantity }}
9 </div>
10 </div>
11</template>Getters in storeToRefs
Getters (computed) are part of 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>Code for this lesson: App.vue
1<script setup>
2import { ref, computed } from 'vue'
3
4// Inventory Store simulation with getters
5const items = ref([
6 { name: 'Oxygen Tank', quantity: 12, category: 'life-support', unit: 'units' },
7 { name: 'Water Filter', quantity: 2, category: 'life-support', unit: 'units' },
8 { name: 'Solar Panel', quantity: 8, category: 'energy', unit: 'units' },
9 { name: 'Battery Pack', quantity: 15, category: 'energy', unit: 'units' },
10 { name: 'Drill Bit', quantity: 20, category: 'mining', unit: 'pcs' },
11 { name: 'Rock Sample Container', quantity: 1, category: 'mining', unit: 'units' }
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 with a parameter
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 - Inventory Getters</h1>
57
58 <div class="stats-bar">
59 <div class="stat-card">
60 <div class="stat-value">{{ totalItems }}</div>
61 <div class="stat-label">Total Items</div>
62 </div>
63 <div class="stat-card">
64 <div class="stat-value" :class="stockStatus.toLowerCase()">{{ stockStatus }}</div>
65 <div class="stat-label">Stock Status</div>
66 </div>
67 <div class="stat-card">
68 <div class="stat-value warning">{{ lowStockItems.length }}</div>
69 <div class="stat-label">Low Stock</div>
70 </div>
71 </div>
72
73 <div class="controls">
74 <input v-model="searchQuery" placeholder="Search..." class="search-input" />
75 <select v-model="selectedCategory" class="select">
76 <option v-for="cat in categories" :key="cat" :value="cat">
77 {{ cat === 'all' ? 'All Categories' : 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 Low stock: {{ 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>Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What are getters in Pinia?
2. How are getters defined in a Composition API store?
These are 2 of 3 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Code editor
Create getters in a Pinia store
- Horizontal ordering
Arrange the elements to define a getter in a Pinia store
- Click in order
Arrange the elements to create a getter with a parameter
- Code editor
Create getters that filter data based on parameters