1. 安装 Pinia
首先,确保你已经安装了 Pinia。
npm install pinia
2. 配置 Pinia
在你的 main.ts
或 main.js
中,创建 Pinia 实例并将其注册到 Vue 应用中。
// main.ts 或 main.js
import { createApp } from 'vue';
import { createPinia } from 'pinia'; // 导入 Pinia
import App from './App.vue';
const app = createApp(App);
const pinia = createPinia(); // 创建 Pinia 实例
app.use(pinia); // 将 Pinia 添加到 Vue 应用中
app.mount('#app');
3. 定义 Pinia Store
在 src/stores
目录下创建一个 authStore.ts
文件,用于管理用户的登录状态和账户信息。
// src/stores/authStore.ts
import { defineStore } from 'pinia';
// 定义 User 类型
interface User {
id: number;
username: string;
email: string;
score: number;
}
export const useAuthStore = defineStore('auth', {
state: () => ({
isLoggedIn: false, // 用户是否登录
user: {} as User, // 存储用户信息
}),
getters: {
// getter 用于从 state 中派生数据
userName: (state) => state.user.username, // 获取用户的用户名
userScore: (state) => state.user.score, // 获取用户的积分
},
actions: {
// actions 用于修改 state 中的数据
login(userData: User) {
this.user = userData; // 更新用户信息
this.isLoggedIn = true; // 更新登录状态
},
logout() {
this.user = {} as User; // 清空用户信息
this.isLoggedIn = false; // 更新登录状态
},
// 示例:增加用户积分的 action
increaseScore(amount: number) {
if (this.isLoggedIn) {
this.user.score += amount; // 增加积分
}
}
}
});
4. 使用 Pinia Store
在 Vue 组件中,可以通过 useAuthStore()
引入并使用 store。在登录时调用 login
方法更新状态,获取用户数据时可以直接使用 getters。
<!-- src/components/Login.vue -->
<template>
<div>
<h1 v-if="!authStore.isLoggedIn">Login</h1>
<h1 v-else>Welcome, {{ authStore.userName }}!</h1>
<div v-if="!authStore.isLoggedIn">
<input v-model="username" placeholder="Username" />
<input v-model="email" placeholder="Email" />
<button @click="login">Login</button>
</div>
<div v-else>
<button @click="logout">Logout</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useAuthStore } from '@/stores/authStore';
const authStore = useAuthStore();
const username = ref('');
const email = ref('');
// 登录操作
function login() {
const user = {
id: 1,
username: username.value,
email: email.value,
score: 100,
};
authStore.login(user); // 调用 store 的 login 方法
}
// 登出操作
function logout() {
authStore.logout(); // 调用 store 的 logout 方法
}
</script>
5. Pinia中的 Getters 和 Actions 的区别
- Getters:
- 目的:用来从 state 中派生或计算数据。
- 特点:是 只读的,不直接修改 state,通常用于对 state 中的数据进行处理或者返回某种计算结果。
- 使用场景:计算派生状态(例如,获取用户的用户名、积分等)。
- Actions:
- 目的:用来 修改 state 和 执行异步操作(如 API 请求)。
- 特点:通过
this
访问state
和getters
,并可以修改state
或执行副作用(比如调用 API 或者增加积分)。 - 使用场景:修改应用状态,触发异步操作(如用户登录、登出等)。
示例:Getters 和 Actions 的区别
export const useAuthStore = defineStore('auth', {
state: () => ({
isLoggedIn: false,
user: {} as User,
}),
getters: {
// Getter 用于从 state 派生信息,不能修改 state
userName: (state) => state.user.username,
userScore: (state) => state.user.score,
},
actions: {
// Action 用于修改 state,执行异步操作
login(userData: User) {
this.user = userData; // 修改 state
this.isLoggedIn = true; // 更新登录状态
},
logout() {
this.user = {} as User; // 清空用户数据
this.isLoggedIn = false; // 设置为未登录
},
increaseScore(amount: number) {
if (this.isLoggedIn) {
this.user.score += amount; // 修改 state
}
},
}
});
6. Pinia 持久化状态(可选)
如果你希望在页面刷新时保持用户的登录状态,可以使用插件将状态持久化到 localStorage
或 sessionStorage
。
首先安装持久化插件:
npm install pinia-plugin-persistedstate
然后在 main.ts
中启用该插件:
// main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import piniaPersist from 'pinia-plugin-persistedstate'; // 导入插件
import App from './App.vue';
const app = createApp(App);
const pinia = createPinia();
pinia.use(piniaPersist); // 启用持久化插件
app.use(pinia);
app.mount('#app');
在 store 中启用持久化:
// src/stores/authStore.ts
import { defineStore } from 'pinia';
interface User {
id: number;
username: string;
email: string;
score: number;
}
export const useAuthStore = defineStore('auth', {
state: () => ({
isLoggedIn: false,
user: {} as User,
}),
actions: {
login(userData: User) {
this.user = userData;
this.isLoggedIn = true;
},
logout() {
this.user = {} as User;
this.isLoggedIn = false;
},
},
persist: true, // 启用持久化
});
在 Pinia 中,除了 state
、getters
和 actions
外,还可以使用 钩子(Hooks)来处理特定的生命周期事件,类似于 Vue 的生命周期钩子。Pinia 提供了几个常用的钩子来增强 store 的功能,下面是如何使用这些钩子的完整示例。
7.Pinia 提供的钩子
$onAction
:监听 actions 被调用的事件。$patch
:用来部分修改 store 的 state,类似于 Vuex 中的 mutation。$subscribe
:监听 store 的变化,类似于 Vuex 中的 getter 和 mutation 订阅。$dispose
:销毁 store。
示例:使用钩子
假设我们有一个用户登录状态的 store,下面演示如何使用钩子来监听 actions 和 state 的变化。
1. 在 store 中使用钩子
// src/stores/authStore.ts
import { defineStore } from 'pinia';
// 定义 User 类型
interface User {
id: number;
username: string;
email: string;
score: number;
}
export const useAuthStore = defineStore('auth', {
state: () => ({
isLoggedIn: false, // 用户是否登录
user: {} as User, // 存储用户信息
}),
getters: {
userName: (state) => state.user.username,
userScore: (state) => state.user.score,
},
actions: {
login(userData: User) {
this.user = userData;
this.isLoggedIn = true;
},
logout() {
this.user = {} as User;
this.isLoggedIn = false;
},
increaseScore(amount: number) {
if (this.isLoggedIn) {
this.user.score += amount;
}
},
},
// 监听 action 的钩子
persist: true,
// 在 store 被创建时调用的钩子
$onAction: (context) => {
console.log('Action was called', context);
// 可以使用 context 来获取 action 的名称和参数
},
// 在 store 的 state 发生变化时调用
$subscribe: (mutation) => {
console.log('Store changed', mutation);
// mutation 包含了变化的类型和发生的状态
},
// 在 store 销毁时调用的钩子
$dispose: () => {
console.log('Store disposed');
},
});
2. 在组件中使用钩子
在组件中调用 Pinia store 时,我们也可以利用钩子来处理一些业务逻辑,例如在登录成功后修改页面内容、发送消息等。
<!-- src/components/Login.vue -->
<template>
<div>
<h1 v-if="!authStore.isLoggedIn">Login</h1>
<h1 v-else>Welcome, {{ authStore.userName }}!</h1>
<div v-if="!authStore.isLoggedIn">
<input v-model="username" placeholder="Username" />
<input v-model="email" placeholder="Email" />
<button @click="login">Login</button>
</div>
<div v-else>
<button @click="logout">Logout</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { useAuthStore } from '@/stores/authStore';
const authStore = useAuthStore();
const username = ref('');
const email = ref('');
// 登录操作
function login() {
const user = {
id: 1,
username: username.value,
email: email.value,
score: 100,
};
authStore.login(user); // 调用 store 的 login 方法
}
// 登出操作
function logout() {
authStore.logout(); // 调用 store 的 logout 方法
}
// 组件挂载时触发
onMounted(() => {
console.log('Component mounted');
authStore.$subscribe((mutation) => {
console.log('Mutation occurred:', mutation);
});
});
// 组件卸载时触发
onBeforeUnmount(() => {
console.log('Component will unmount');
authStore.$dispose(); // 清理 store 的钩子
});
</script>
3. 使用 $onAction
和 $subscribe
$onAction
:它会在每次调用 store 中的 action 时触发,可以用来记录或执行副作用。$subscribe
:它会监听 store 的 state 变化,当 state 被修改时,$subscribe
会收到 mutation 通知,可以用来做额外的响应(如缓存、发送请求等)。
4. 使用持久化存储和钩子
如果你希望在应用重载时保留 store 状态(例如登录信息),可以结合 Pinia 的持久化插件使用。
// src/stores/authStore.ts
import { defineStore } from 'pinia';
import piniaPersist from 'pinia-plugin-persistedstate'; // 插件
export const useAuthStore = defineStore('auth', {
state: () => ({
isLoggedIn: false,
user: {} as User,
}),
actions: {
login(userData: User) {
this.user = userData;
this.isLoggedIn = true;
},
logout() {
this.user = {} as User;
this.isLoggedIn = false;
},
},
// 启用持久化
persist: true, // 状态持久化
$onAction: (context) => {
console.log('Action called:', context);
},
$subscribe: (mutation) => {
console.log('Store changed:', mutation);
},
$dispose: () => {
console.log('Store disposed');
},
});
5. 总结:钩子的功能和使用
Pinia 提供的钩子机制可以帮助我们监听 store 的状态变化、捕获 action 的调用,以及处理一些副作用,增强了 store 的灵活性。
$onAction
:监听 actions 的调用,可用于记录日志、调试等。$subscribe
:监听 store 的 state 变化,用于响应式操作。$dispose
:销毁 store 时触发,可以做一些清理工作。
在使用这些钩子时,可以帮助你更好地管理 store 的状态变化,并且便于扩展和维护。