如何在Pinia Store中调用$toast?附示例(Vue3选项式API)
在Pinia Store中处理提示与Axios的最佳实践
一、直接在Store中调用toaster/swal的实现方式
如果只是快速实现需求,直接在Store中导入库或通过全局属性访问是可行的:
1. 直接导入toaster库(以vue-toastification为例)
// stores/yourStore.js import { defineStore } from 'pinia' import axios from 'axios' import { useToast } from 'vue-toastification' const toast = useToast() export const useYourStore = defineStore('yourStore', { actions: { async fetchData() { try { const response = await axios.get('/api/data') toast.success('数据获取成功!') return response.data } catch (error) { toast.error(`请求失败:${error.message}`) throw error // 抛出错误让组件可处理后续逻辑 } } } })
2. 通过app全局属性访问(适合$swal这类挂载到全局的工具)
若已将swal挂载到app全局属性(如app.config.globalProperties.$swal = Swal),可通过Pinia的this.$app访问:
// stores/yourStore.js import { defineStore } from 'pinia' import axios from 'axios' export const useYourStore = defineStore('yourStore', { actions: { async submitForm(data) { try { await axios.post('/api/submit', data) this.$app.config.globalProperties.$swal('成功!', '表单提交完成', 'success') } catch (error) { this.$app.config.globalProperties.$swal('失败!', error.message, 'error') throw error } } } })
二、最佳实践:让Store聚焦业务,UI逻辑交给组件
Store的核心职责是管理状态、处理业务逻辑,耦合UI提示会导致Store难以复用、测试,违背关注点分离原则。最佳方案是:
- Store只负责发起请求、处理业务,成功/失败时返回结果或抛出错误
- 组件调用Store的action,在组件内处理UI提示
示例实现
1. Store文件(纯业务逻辑)
// stores/yourStore.js import { defineStore } from 'pinia' import axios from 'axios' export const useYourStore = defineStore('yourStore', { state: () => ({ data: null }), actions: { async fetchData() { try { const response = await axios.get('/api/data') this.data = response.data return { success: true, message: '数据获取成功' } } catch (error) { return { success: false, message: `请求失败:${error.message}` } } }, async submitForm(data) { try { await axios.post('/api/submit', data) return { success: true, message: '表单提交成功' } } catch (error) { throw new Error(`提交失败:${error.message}`) } } } })
2. 组件文件(处理UI提示)
<template> <button @click="handleFetch">获取数据</button> <button @click="handleSubmit">提交表单</button> </template> <script> import { useYourStore } from '@/stores/yourStore' import { useToast } from 'vue-toastification' import Swal from 'sweetalert2' export default { setup() { const store = useYourStore() const toast = useToast() const handleFetch = async () => { const result = await store.fetchData() result.success ? toast.success(result.message) : toast.error(result.message) } const handleSubmit = async () => { try { const result = await store.submitForm({ name: 'test' }) Swal.fire('成功', result.message, 'success') } catch (error) { Swal.fire('失败', error.message, 'error') } } return { handleFetch, handleSubmit } } } </script>
三、进阶方案:封装Axios拦截器统一处理提示
如果多个请求都需要提示,可封装Axios拦截器统一处理,避免重复代码:
// utils/axios.js import axios from 'axios' import { useToast } from 'vue-toastification' import Swal from 'sweetalert2' const toast = useToast() const instance = axios.create({ baseURL: '/api' }) // 响应拦截器 instance.interceptors.response.use( (response) => { // 可根据后端返回的code判断是否提示 if (response.data.code === 200 && response.data.message) { toast.success(response.data.message) } return response }, (error) => { const message = error.response?.data?.message || '请求出错' Swal.fire('错误', message, 'error') return Promise.reject(error) } ) export default instance
之后在Store和组件中使用这个封装后的Axios实例,既统一了提示逻辑,又保持Store的纯净性。
内容的提问来源于stack exchange,提问作者KHALED OGHLI
相关产品推荐
相关产品推荐

