@extends('layouts.app_copy')
Actions 是 Pinia 中处理业务逻辑的地方,类似于组件中的方法。它们可以用来执行同步或异步操作,修改状态(通过 this 直接修改 state),或调用其他 actions。
在 Pinia store 中,actions 定义在 actions 属性中:
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
user: null,
loading: false
}),
actions: {
// 同步 action
increment() {
this.count++
},
// 带参数的 action
incrementBy(amount) {
this.count += amount
},
// 异步 action
async fetchUser(userId) {
this.loading = true
try {
const response = await fetch(`https://api.example.com/users/${userId}`)
this.user = await response.json()
} catch (error) {
console.error('Error fetching user:', error)
} finally {
this.loading = false
}
}
}
})
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">+1</button>
<button @click="incrementBy(5)">+5</button>
<button @click="fetchUser(1)">获取用户</button>
<div v-if="loading">加载中...</div>
<div v-else-if="user">
用户名: {{ user.name }}
</div>
</div>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// 解构 store(保持响应性)
const { count, user, loading } = storeToRefs(counterStore)
// 解构 actions
const { increment, incrementBy, fetchUser } = counterStore
</script>
<script>
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counterStore = useCounterStore()
const handleClick = async () => {
await counterStore.fetchUser(1)
console.log('User fetched:', counterStore.user)
}
return {
counterStore,
handleClick
}
}
}
</script>
actions: {
async login(credentials) {
const response = await this.authRequest(credentials)
this.setUser(response.user)
this.setToken(response.token)
},
authRequest(credentials) {
return fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials)
}).then(res => res.json())
},
setUser(user) {
this.user = user
},
setToken(token) {
this.token = token
}
}
actions: {
updateProfile(data) {
// 方式1:直接修改
this.name = data.name
this.email = data.email
this.avatar = data.avatar
// 方式2:使用 $patch 批量更新(性能更好)
this.$patch({
name: data.name,
email: data.email,
avatar: data.avatar
})
// 方式3:使用 $patch 函数
this.$patch((state) => {
state.name = data.name
state.email = data.email
state.avatar = data.avatar
})
}
}
import { useAuthStore } from './authStore'
import { useCartStore } from './cartStore'
export const useOrderStore = defineStore('order', {
actions: {
async checkout() {
const authStore = useAuthStore()
const cartStore = useCartStore()
if (!authStore.isAuthenticated) {
throw new Error('请先登录')
}
const order = {
userId: authStore.user.id,
items: cartStore.items,
total: cartStore.total
}
// 调用 API
const response = await this.createOrder(order)
// 清空购物车
cartStore.clearCart()
return response
},
async createOrder(orderData) {
// API 调用
}
}
})
// stores/todo.js
import { defineStore } from 'pinia'
export const useTodoStore = defineStore('todo', {
state: () => ({
todos: [],
filter: 'all',
loading: false,
error: null
}),
getters: {
filteredTodos(state) {
if (state.filter === 'active') {
return state.todos.filter(todo => !todo.completed)
}
if (state.filter === 'completed') {
return state.todos.filter(todo => todo.completed)
}
return state.todos
},
pendingCount(state) {
return state.todos.filter(todo => !todo.completed).length
}
},
actions: {
async fetchTodos() {
this.loading = true
this.error = null
try {
const response = await fetch('/api/todos')
this.todos = await response.json()
} catch (error) {
this.error = error.message
console.error('Failed to fetch todos:', error)
} finally {
this.loading = false
}
},
async addTodo(title) {
if (!title.trim()) return
const todo = {
id: Date.now(),
title,
completed: false,
createdAt: new Date().toISOString()
}
try {
// 乐观更新
this.todos.unshift(todo)
// 实际 API 调用
await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(todo)
})
} catch (error) {
// 失败时回滚
this.todos = this.todos.filter(t => t.id !== todo.id)
this.error = '添加失败,请重试'
}
},
async toggleTodo(id) {
const todo = this.todos.find(t => t.id === id)
if (todo) {
const originalCompleted = todo.completed
// 乐观更新
todo.completed = !todo.completed
try {
await fetch(`/api/todos/${id}`, {
method: 'PATCH',
body: JSON.stringify({ completed: todo.completed })
})
} catch (error) {
// 失败时恢复
todo.completed = originalCompleted
this.error = '更新失败,请重试'
}
}
},
setFilter(filter) {
if (['all', 'active', 'completed'].includes(filter)) {
this.filter = filter
}
},
clearCompleted() {
const completedIds = this.todos
.filter(todo => todo.completed)
.map(todo => todo.id)
// 移除本地
this.todos = this.todos.filter(todo => !todo.completed)
// 批量删除 API 调用
completedIds.forEach(id => {
fetch(`/api/todos/${id}`, { method: 'DELETE' })
})
}
}
})
Pinia Actions 是处理业务逻辑的核心,主要特点:
this 访问和修改状态通过合理使用 Actions,可以使状态管理更加清晰、可维护,同时保持组件逻辑的简洁。