Vue3 Pinia Store 新建store示例、使用store示例

1、新建store示例

新建store示例代码:userMenu.ts

import { defineStore } from "pinia";  // 导入 Pinia 的 defineStore 方法
import { ref } from "vue";           // 导入 Vue 的响应式 API ref
import { type Menu } from "@/interface"; // 导入自定义的 Menu 类型

// 创建一个名为 'userMenu' 的 Store
// 定义 Store: 使用 Pinia 的 Setup 语法形式(另外还有 Options 语法形式),默认不提供 $reset() 方法
const useUserMenuStore = defineStore(
  "userMenu",  // Store 的唯一标识名
  () => {      // 使用组合式 API 的 setup 函数写法
    // 1. 定义当前菜单状态(响应式引用)
    const menu = ref<Menu[]>([]);  // 创建一个存储 Menu 数组的响应式引用

    // 2. 设置菜单的方法
    const setMenu = (newMenu: Menu[]) => {
      menu.value = newMenu;  // 更新菜单数据
    };

    // 3. 清除菜单的方法
    const removeMenu = () => {
      menu.value = [];       // 清空当前菜单
      pastMenu.value = [];   // 同时清空历史菜单
    };

    // 4. 定义历史菜单状态(响应式引用)
    const pastMenu = ref<Menu[]>([]);  // 创建一个存储历史菜单的响应式引用

    // 5. 设置历史菜单的方法
    const setPastMenu = (newMenu: Menu[]) => {
      pastMenu.value = newMenu;  // 更新历史菜单数据
    };

    // 暴露所有需要外部访问的状态和方法
    return { menu, setMenu, removeMenu, pastMenu, setPastMenu };
  },
  { persist: true }  // 启用持久化插件配置(页面刷新后数据不丢失)
);

export default useUserMenuStore;  // 导出 Store

核心概念解释:

  1. defineStore

    • Pinia 的核心方法,用于创建 Store

    • 第一个参数是 Store 的唯一名称

    • 第二个参数是 setup 函数,用组合式 API 编写

    • 第三个参数是配置对象,这里启用了持久化

  2. ref

    • Vue 的响应式 API,用于创建响应式数据

    • ref<Menu[]> 表示这是一个存储 Menu 类型数组的响应式引用

    • 通过 .value 访问/修改值(但在模板中会自动解包,不需要 .value)

  3. 类型系统

    • Menu 是自定义类型(来自 @/interface)

    • TypeScript 泛型 <Menu[]> 确保数据类型的正确性

  4. 方法功能

    • setMenu:更新当前菜单

    • removeMenu:清空所有菜单数据

    • setPastMenu:更新历史菜单

  5. 持久化配置

    • { persist: true } 表示启用状态持久化

    • 需要配合 pinia-plugin-persistedstate 插件使用

    • 数据会保存在 localStorage 中,防止页面刷新丢失

使用场景示例:

javascript

// 在组件中使用
import useUserMenuStore from '@/stores/userMenu';

const menuStore = useUserMenuStore();

// 更新菜单
menuStore.setMenu([{ id: 1, name: '首页' }]);

// 获取当前菜单
console.log(menuStore.menu); 

// 清空菜单
menuStore.removeMenu();

新手需要注意:

  1. 响应式规则

    • 在 JS 中修改状态需要使用 .value

    • 在模板中直接使用变量名即可

  2. Store 的生命周期

    • 单例模式:整个应用共享同一个 Store 实例

    • 持久化数据会一直保留,直到手动清除或用户清除浏览器缓存

  3. 类型安全

    • TypeScript 的类型约束可以帮助减少错误

    • 如果传递错误类型的参数,编译时会报错

这个 Store 的设计非常适合管理需要持久化的全局界面状态(比如用户菜单、主题设置等),通过分离状态逻辑使组件更专注于视图渲染。

2、使用store示例

方案 1:使用 computed 保持响应式链接
import useProgressCtrlStore from "../stores";
import { computed } from "vue";

const progressCtrlStore = useProgressCtrlStore();
const tableData = computed(() => progressCtrlStore.applyBasicInfoListData);
方案 2:使用 Pinia 的 storeToRefs
import useProgressCtrlStore from "../stores";
import { storeToRefs } from "pinia";

const progressCtrlStore = useProgressCtrlStore();
const { applyBasicInfoListData } = storeToRefs(progressCtrlStore);
const tableData = applyBasicInfoListData; // 现在是一个响应式 ref
方案 3:直接操作 Store 属性(推荐)
import useProgressCtrlStore from "../stores";

const progressCtrlStore = useProgressCtrlStore();

// 在模板中直接使用:
<el-table
      ref="table"
      :data="progressCtrlStore.applyBasicInfoListData"
      :border="true"
      highlight-current-row
      style="width: 100%; height: 100%"
      @row-click="onTableRowClick">

// 在 JS 中访问:
progressCtrlStore.applyBasicInfoListData.map(...)

不同数据类型的具体表现:

数据类型直接赋值结果正确响应式方案
基本类型 (string/number)❌ 失去响应性使用 computed 或 ref
响应式数组 (reactive)✅ 保持内容响应性*推荐使用 storeToRefs
响应式对象 (reactive)✅ 保持属性响应性*推荐保持原始引用

<think>我们正在讨论的是在Vue3Pinia store安装后执行回调函数的方法。根据用户的问题,他们可能是在使用Pinia管理状态时,希望在store初始化完成后执行一些操作。 在Pinia中,store是通过`defineStore`定义的,并且通常使用`useStore()`函数来获取store实例。然而,store的初始化是同步的,但有时我们可能需要知道store何时被完全设置好(例如,如果store中有异步初始化操作)。 根据引用[3],Pinia支持插件(plugins),我们可以通过插件在store创建时执行一些操作。此外,Piniastore本身也提供了一些内置方法,如`$onAction`和`$subscribe`,但这些主要用于监听action和state的变化。 另外,引用[2]提到了在store中可以使用action来执行异步操作,然后通过返回Promise来让调用方知道异步操作完成。 因此,我们可以通过以下几种方法来实现“store安装后执行回调”: ### 方法1:在组件中使用store的action并处理其Promise 如果store的初始化包含异步操作(例如从API获取数据),我们可以在action中返回Promise,然后在组件中调用该action并使用`.then()`或`async/await`来执行回调。 **store定义**: ```javascript import { defineStore } from &#39;pinia&#39;; export const useMyStore = defineStore(&#39;myStore&#39;, { actions: { async init() { // 异步初始化操作 await this.fetchData(); }, async fetchData() { // 模拟异步请求 this.data = await fetch(&#39;/api/data&#39;).then(res => res.json()); } }, state: () => ({ data: null }) }); ``` **组件中使用**: ```vue <script setup> import { useMyStore } from &#39;./store/myStore&#39;; const store = useMyStore(); // 调用init action,并在初始化完成后执行回调 store.init().then(() => { console.log(&#39;Store初始化完成,数据已加载&#39;); }); </script> ``` ### 方法2:使用Pinia的插件(plugin)在store创建时执行回调 我们可以编写一个Pinia插件,在store被创建时(即安装后)执行一些操作。插件可以访问到store实例,因此我们可以在插件中执行一些初始化逻辑,或者添加一些全局的监听。 **编写插件**: ```javascript // piniaPlugin.js export function myPiniaPlugin(context) { const { store } = context; // 在这里可以执行一些初始化操作 console.log(`Store ${store.$id} 已创建`); // 如果store有初始化方法,可以在这里调用 if (store.init) { store.init(); } // 或者,我们可以添加一个回调队列,让store可以注册回调 store.callbacks = []; store.onReady = (callback) => { store.callbacks.push(callback); }; // 假设我们有一个异步初始化的过程 // 在初始化完成后,执行所有回调 setTimeout(() => { store.callbacks.forEach(cb => cb()); }, 1000); } ``` **在应用中使用插件**: ```javascript import { createApp } from &#39;vue&#39;; import { createPinia } from &#39;pinia&#39;; import { myPiniaPlugin } from &#39;./piniaPlugin&#39;; const pinia = createPinia(); pinia.use(myPiniaPlugin); // 使用插件 const app = createApp(App); app.use(pinia); app.mount(&#39;#app&#39;); ``` **在store中定义初始化方法**: 在插件中我们调用了`store.init`(如果存在),所以可以在store中定义这个方法: ```javascript defineStore(&#39;myStore&#39;, { actions: { init() { // 初始化逻辑 } } }); ``` **在组件中注册回调**: ```vue <script setup> import { useMyStore } from &#39;./store/myStore&#39;; const store = useMyStore(); store.onReady(() => { console.log(&#39;Store已经准备好&#39;); }); </script> ``` ### 方法3:利用store的`$subscribe`或`$onAction`方法 如果我们只是想在store的state变化或某个action被调用后执行回调,可以使用这些内置方法。 例如,在组件中: ```vue <script setup> import { useMyStore } from &#39;./store/myStore&#39;; import { onMounted } from &#39;vue&#39;; const store = useMyStore(); onMounted(() => { // 监听state变化 store.$subscribe((mutation, state) => { // 当state变化时执行 }); // 监听action调用 store.$onAction(({ name, after }) => { after(() => { // 在action执行完成后 if (name === &#39;init&#39;) { console.log(&#39;init action完成,执行回调&#39;); } }); }); }); </script> ``` ### 方法4:在store的getter中返回一个Promise(不推荐) 这种方法比较复杂,且容易造成混乱,通常不推荐。但作为一种思路,我们可以让store的某个getter返回一个Promise,该Promise在初始化完成后resolve。 ### 总结 - **如果store需要异步初始化**:使用方法1,在action中返回Promise,然后在组件中调用该action并处理Promise。 - **如果需要在每个store创建时都执行一些逻辑**:使用方法2,编写Pinia插件。 - **如果需要在特定状态变化或action完成后执行回调**:使用方法3使用`$subscribe`或`$onAction`。 ### 注意事项 - 避免在store的构造函数(setup函数)中直接进行异步操作而不提供等待机制,因为这样组件无法知道初始化何时完成。 - 在插件中,我们可以为store添加新的属性和方法(如上面示例中的`onReady`方法),但要注意类型扩展(TypeScript)的问题。 ### 相关问题 1. 如何在Pinia store中正确使用TypeScript进行类型定义? 2. Pinia插件有哪些实际应用场景? 3. 如何测试使用了异步初始化的Pinia store? 4.Vue3中,如何全局处理Pinia store的异步操作错误? 5. PiniastoreVuex的module有何异同? 6. 如何在Pinia中实现多个store之间的通信? 以上方法应该能够帮助用户解决在Pinia store安装后执行回调的需求。根据具体场景选择最合适的方法。</think>### Vue3 Pinia Store 安装后执行回调函数的完整指南 在 Vue3使用 Pinia 时,可以通过以下方法在 store 安装完成后执行回调函数: #### 方法 1:使用 Pinia 插件(推荐) ```typescript // plugins/storeReady.ts import { PiniaPluginContext } from &#39;pinia&#39; export function storeReadyPlugin(context: PiniaPluginContext) { return { // 添加全局的 onReady 方法 onReady: (callback: () => void) => { // 确保所有异步操作完成 Promise.resolve().then(callback) } } } // main.ts import { createApp } from &#39;vue&#39; import { createPinia } from &#39;pinia&#39; import { storeReadyPlugin } from &#39;./plugins/storeReady&#39; const pinia = createPinia() pinia.use(storeReadyPlugin) // 注册插件 createApp(App).use(pinia).mount(&#39;#app&#39;) ``` **在组件中使用**: ```vue <script setup lang="ts"> import { useUserStore } from &#39;@/stores/user&#39; const userStore = useUserStore() // 使用插件添加的 onReady 方法 userStore.onReady(() => { console.log(&#39;UserStore 已完全初始化&#39;) // 执行初始化后操作 userStore.fetchUserData() }) </script> ``` [^3] #### 方法 2:在 store使用 action + Promise ```typescript // stores/user.ts import { defineStore } from &#39;pinia&#39; export const useUserStore = defineStore(&#39;user&#39;, { state: () => ({ loaded: false, userData: null }), actions: { // 初始化方法返回 Promise initialize() { return new Promise<void>((resolve) => { // 模拟异步初始化 setTimeout(() => { this.loaded = true resolve() }, 500) }) } } }) ``` **在组件中调用**: ```vue <script setup lang="ts"> import { onMounted } from &#39;vue&#39; import { useUserStore } from &#39;@/stores/user&#39; const userStore = useUserStore() onMounted(async () => { // 等待初始化完成 await userStore.initialize() // 初始化后执行回调 console.log(&#39;Store 初始化完成&#39;) // 执行后续操作... }) </script> ``` #### 方法 3使用 $subscribe 监听状态变化 ```vue <script setup lang="ts"> import { storeToRefs } from &#39;pinia&#39; import { useUserStore } from &#39;@/stores/user&#39; const userStore = useUserStore() const { isInitialized } = storeToRefs(userStore) // 需要 store 中有此状态 // 监听初始化状态变化 userStore.$subscribe((mutation, state) => { if (state.isInitialized) { console.log(&#39;Store 已初始化&#39;) // 执行回调操作 } }) </script> ``` [^2] #### 方法 4:在 store 中添加自定义钩子 ```typescript // stores/baseStore.ts import { defineStore } from &#39;pinia&#39; type Callback = () => void export const useBaseStore = defineStore(&#39;base&#39;, { state: () => ({ readyCallbacks: [] as Callback[], isReady: false }), actions: { // 添加回调到队列 onReady(callback: Callback) { if (this.isReady) { callback() } else { this.readyCallbacks.push(callback) } }, // 标记为就绪并执行所有回调 markAsReady() { this.isReady = true this.readyCallbacks.forEach(cb => cb()) this.readyCallbacks = [] } } }) ``` **在具体 store使用**: ```typescript // stores/user.ts import { defineStore } from &#39;pinia&#39; import { useBaseStore } from &#39;./baseStore&#39; export const useUserStore = defineStore(&#39;user&#39;, { actions: { async init() { const baseStore = useBaseStore() // 执行初始化逻辑... await fetchUserData() // 标记为就绪状态 baseStore.markAsReady() } } }) ``` ### 最佳实践建议 1. **初始化顺序控制**: ```typescript // main.ts app.use(pinia) // 等待所有store初始化 Promise.all([ useUserStore().init(), useProductStore().init() ]).then(() => { app.mount(&#39;#app&#39;) console.log(&#39;所有store初始化完成&#39;) }) ``` 2. **组合式API封装**: ```typescript // composables/useStoreReady.ts import { onMounted } from &#39;vue&#39; import { useUserStore } from &#39;@/stores/user&#39; export function useStoreReady(callback: () => void) { const store = useUserStore() onMounted(async () => { if (!store.isInitialized) { await store.initialize() } callback() }) } ``` ### 注意事项 1. **响应式处理**:使用 `storeToRefs` 保持解构后的响应式 ```typescript import { storeToRefs } from &#39;pinia&#39; const store = useUserStore() const { userData } = storeToRefs(store) // 保持响应式 ``` [^2] 2. **避免重复初始化**:在 store 中添加状态标志 ```typescript state: () => ({ initialized: false }), actions: { async init() { if (this.initialized) return // 初始化逻辑... this.initialized = true } } ``` 3. **错误处理**:在异步初始化中添加错误处理 ```typescript actions: { async initialize() { try { // 初始化逻辑 } catch (error) { console.error(&#39;初始化失败&#39;, error) // 处理错误状态 } } } ``` ### 适用场景对比 | 方法 | 适用场景 | 优点 | 缺点 | |--------------------|---------------------------------|--------------------------|--------------------| | Pinia 插件 | 全局store初始化监听 | 集中管理,可复用 | 需要额外插件代码 | | Action + Promise | 单个store初始化控制 | 简单直接,易于理解 | 需手动调用 | | $subscribe | 响应特定状态变化 | 内置API,无需额外代码 | 可能触发多次 | | 自定义钩子 | 复杂初始化流程 | 高度可定制化 | 实现较复杂 | ### 相关问题 1. 如何在 Pinia 中处理多个 store 之间的初始化依赖关系? 2. Pinia 插件如何配合 TypeScript 进行类型扩展? 3. 在 SSR 场景下,Pinia store 的初始化有何特殊注意事项? 4. 如何为 Pinia store 的初始化过程编写单元测试? 5. Pinia 的 $onAction 和 $subscribe 方法有何区别?[^2] 6. Vue3 的 provide/inject 如何与 Pinia 配合使用? 7. 如何在 Pinia 中实现跨 store 的状态同步?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值