Actions to funkcje modyfikujące state i wykonujące operacje - jak komendy kontroli misji NOVA LAB. To tu znajduje się logika biznesowa: pobieranie danych, walidacja, obsługa błędów.
W Composition API actions to zwykłe funkcje:
1import { defineStore } from 'pinia'
2import { ref } from 'vue'
3
4export const useCrewStore = defineStore('crew', () => {
5 const members = ref([])
6 const selectedMember = ref(null)
7
8 // Prosta action
9 function selectMember(member) {
10 selectedMember.value = member
11 }
12
13 // Action z logiką
14 function addMember(member) {
15 if (members.value.length >= 8) {
16 throw new Error('Maximum crew size reached!')
17 }
18 members.value.push({
19 ...member,
20 id: Date.now(),
21 joinedAt: new Date()
22 })
23 }
24
25 function removeMember(id) {
26 members.value = members.value.filter(m => m.id !== id)
27 if (selectedMember.value?.id === id) {
28 selectedMember.value = null
29 }
30 }
31
32 return { members, selectedMember, selectMember, addMember, removeMember }
33})Actions mogą być asynchroniczne - idealne do pobierania danych z API:
1export const useCrewStore = defineStore('crew', () => {
2 const members = ref([])
3 const isLoading = ref(false)
4 const error = ref(null)
5
6 async function fetchCrew() {
7 isLoading.value = true
8 error.value = null
9
10 try {
11 const response = await fetch('/api/crew')
12 if (!response.ok) {
13 throw new Error('Failed to fetch crew data')
14 }
15 members.value = await response.json()
16 } catch (e) {
17 error.value = e.message
18 } finally {
19 isLoading.value = false
20 }
21 }
22
23 async function updateMemberRole(id, newRole) {
24 try {
25 const response = await fetch(`/api/crew/${id}`, {
26 method: 'PATCH',
27 headers: { 'Content-Type': 'application/json' },
28 body: JSON.stringify({ role: newRole })
29 })
30
31 if (!response.ok) throw new Error('Update failed')
32
33 const updated = await response.json()
34 const index = members.value.findIndex(m => m.id === id)
35 if (index !== -1) {
36 members.value[index] = updated
37 }
38 } catch (e) {
39 error.value = e.message
40 throw e
41 }
42 }
43
44 return { members, isLoading, error, fetchCrew, updateMemberRole }
45})Wzorzec try/catch/finally jest standardem w asynchronicznych actions:
1async function saveData(data) {
2 isLoading.value = true
3 error.value = null
4
5 try {
6 const result = await apiCall(data)
7 // Sukces - aktualizuj state
8 items.value.push(result)
9 return result
10 } catch (e) {
11 // Błąd - zapisz komunikat
12 error.value = e.message
13 throw e // Przekaż błąd do komponentu
14 } finally {
15 // Zawsze - wyłącz loading
16 isLoading.value = false
17 }
18}1<script setup>
2import { onMounted } from 'vue'
3import { useCrewStore } from '@/stores/crew'
4
5const crewStore = useCrewStore()
6
7// Wywołanie przy montowaniu
8onMounted(() => {
9 crewStore.fetchCrew()
10})
11
12// Handler z obsługą błędu
13async function handleAddMember(member) {
14 try {
15 await crewStore.addMember(member)
16 } catch (e) {
17 alert('Error: ' + e.message)
18 }
19}
20</script>