Pinia 是 Vue 的状态管理库,类似于 Vuex,但具有更简单的 API 和更好的性能。它提供了一种更简单、更灵活的方式来管理应用程序的状态。
1. 安装 Pinia
在 Vue 3 项目中安装 Pinia,可以使用 npm 或 yarn:
npm install pinia
# or
yarn add pinia2. 基本使用
2.1 创建 Pinia 实例
在 main.js 文件中创建 Pinia 实例,并将其传递给 Vue 应用程序:
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.mount("#app");2.2 创建 Store
在 src 目录下创建一个 stores 目录,并在其中创建一个 store 文件,例如 user.js:
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
  state: () => ({
    name: "",
    age: 0,
  }),
  actions: {
    setName(name) {
      this.name = name;
    },
    setAge(age) {
      this.age = age;
    },
  },
  getters: {
    fullName: (state) => `${state.name} ${state.age}`,
  },
});2.3 使用 Store
在组件中使用 store,可以通过 useStore 函数来获取 store 实例:
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();
userStore.name; // 访问 state
userStore.setName("zhang san"); // 调用 action
userStore.setAge(18); // 调用 action
userStore.fullName; // 访问 getter3. 示例
3.1 订阅 $onAction
$onAction 用于订阅 store 中的 action 执行。它可以在 action 执行前、执行后或发生错误时进行拦截和处理。
3.1.1 日志记录
// stores/user.js
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
  state: () => ({
    name: "",
    age: 0,
  }),
  actions: {
    async updateUserInfo(name, age) {
      this.name = name;
      this.age = age;
    },
  },
});
// 组件中
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();
// 订阅所有 action
userStore.$onAction(
  ({
    name, // action 名称
    args, // 传递给 action 的参数数组
    store, // store 实例
    after, // action 执行后的钩子
    onError, // action 执行出错时的钩子
  }) => {
    // action 执行前的逻辑
    console.log(`Action ${name} started with args:`, args);
    // action 执行后的逻辑
    after((result) => {
      console.log(`Action ${name} completed with result:`, result);
    });
    // action 执行出错时的逻辑
    onError((error) => {
      console.error(`Action ${name} failed with error:`, error);
    });
  }
);3.1.2 性能监控
const userStore = useUserStore();
userStore.$onAction(({ name, args, store, after }) => {
  const startTime = performance.now();
  after(() => {
    const endTime = performance.now();
    console.log(`Action ${name} took ${endTime - startTime}ms to execute`);
  });
});3.1.3 错误处理和重试机制
// stores/user.js
export const useUserStore = defineStore("user", {
  state: () => ({
    name: "",
    age: 0,
  }),
  actions: {
    async fetchUserData() {
      // 模拟 API 调用
      const response = await fetch("/api/user");
      const data = await response.json();
      this.name = data.name;
      this.age = data.age;
    },
  },
});
// 组件中
const userStore = useUserStore();
userStore.$onAction(({ name, args, store, after, onError }) => {
  let retries = 0;
  const maxRetries = 3;
  onError(async (error) => {
    if (retries < maxRetries) {
      retries++;
      console.log(`Retrying action ${name}, attempt ${retries}`);
      await store.fetchUserData();
    } else {
      console.error(`Action ${name} failed after ${maxRetries} retries`);
    }
  });
});3.1.4 权限控制
// stores/user.js
export const useUserStore = defineStore("user", {
  state: () => ({
    name: "",
    age: 0,
    role: "user",
  }),
  actions: {
    updateUserInfo(name, age) {
      this.name = name;
      this.age = age;
    },
    deleteUser() {
      // 删除用户的操作
    },
  },
});
// 在组件中使用
const userStore = useUserStore();
userStore.$onAction(({ name, args, store, after, onError }) => {
  // 检查权限
  if (name === "deleteUser" && store.role !== "admin") {
    onError(new Error("Permission denied"));
    return;
  }
  after(() => {
    console.log(`Action ${name} executed successfully`);
  });
});3.1.5 取消订阅
$onAction 的返回值是一个函数,调用该函数可以取消订阅:
const unsubscribe = userStore.$onAction(({ name, after }) => {
  after(() => {
    console.log(`Action ${name} completed`);
  });
});
// 取消订阅
unsubscribe();3.2 订阅 $subscribe
$subscribe 用于订阅 store 中的 state 变化。它可以在 state 变化时进行拦截和处理。
const userStore = useUserStore();
userStore.$subscribe((mutation, state) => {
  // mutation 是一个对象,包含以下属性:
  // type: 变化的类型,例如 "direct" 或 "patch"
  // storeId: store 的 ID
  // payload: 变化的 payload
  // 检查是否是 name 属性的变化
  if (
    mutation.type === "direct" &&
    mutation.storeId === "user" &&
    mutation.payload.name
  ) {
    // 同步 name 属性到其他地方
  }
});3.3 $patch
$patch 用于批量更新 store 中的 state。它可以在一次操作中更新多个属性,而不需要逐个调用 set 方法。
const userStore = useUserStore();
userStore.$patch({
  name: "zhang san",
  age: 18,
});3.4 $reset
$reset 用于重置 store 中的 state 到初始状态。它可以在需要重置 store 中的所有数据时使用。
const userStore = useUserStore();
userStore.$reset();3.5 持久化 Store
// main.js
import { createPersistedState } from "pinia-plugin-persistedstate";
import { createPinia } from "pinia";
const pinia = createPinia();
pinia.use(createPersistedState());
app.use(pinia);
app.mount("#app");
// user.js
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
  state: () => ({
    firstname: "",
    lastname: "",
  }),
  actions: {
    setFirstname(name) {
      this.firstname = name;
    },
    setLastname(name) {
      this.lastname = name;
    },
  },
  getters: {
    fullName: (state) => `${state.firstname} ${state.lastname}`,
    }
  },
  persist: true, // 启用持久化存储
});3.6 路由守卫
// main.js
import { createRouter, createWebHistory } from "vue-router";
import { createPinia } from "pinia";
import { useUserStore } from "./stores/user";
const router = createRouter({
  history: createWebHistory(),
  routes: [
    // 路由配置
  ],
});
router.beforeEach((to, from, next) => {
  const userStore = useUserStore();
  if (to.meta.requiresAuth && !userStore.isAuthenticated) {
    next({ name: "login" });
  } else {
    next();
  }
});
const pinia = createPinia();
pinia.use(({ store }) => {
  store.$subscribe((mutation, state) => {
    if (mutation.type === "direct" && mutation.storeId === "user") {
      // 检查是否需要重新导航
      if (mutation.payload.isAuthenticated) {
        router.push({ name: "home" });
      }
    }
  });
});
app.use(router);
app.use(pinia);
app.mount("#app");3.7 热更新
// main.js
import { createApp } from "vue";
import { createPinia, acceptHMRUpdate } from "pinia";
import App from "./App.vue";
const app = createApp(App);
const pinia = createPinia();
pinia.use(({ store }) => {
  store.$subscribe((mutation, state) => {
    if (mutation.type === "direct" && mutation.storeId === "user") {
      // 检查是否需要重新导航
      if (mutation.payload.isAuthenticated) {
        router.push({ name: "home" });
      }
    }
  });
});
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(app, import.meta.hot));
}
app.use(pinia);
app.mount("#app"); 原文链接:https://code.ifrontend.net/archives/323,转载请注明出处。		    			
		             
	
评论0