简介
Pinia 是 Vue 3 官方推荐的状态管理库,也是 Vuex 的替代方案之一。它更轻量、更现代化,并提供更好的 TypeScript 支持。
安装 Pinia
首先,确保你已经安装了Vue3 并且初始化了项目。
npm
npm install pinia
yarn
yarn add pinia
配置Pinia
在 main.ts 中创建并配置 Pinia
// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.mount('#app');
定义Store
在 src/stores 目录中创建 store 文件,比如 counter.ts。
// src/stores/counter.ts
import { defineStore } from 'pinia';
// 使用 TypeScript 接口定义状态类型
interface CounterState {
count: number;
}
// 定义 store
export const useCounterStore = defineStore({
id: 'counter',
state: (): CounterState => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
incrementBy(amount: number) {
this.count += amount;
}
}
});
组件中使用
<!-- src/components/CounterComponent.vue -->
<template>
<div>
<h2>Counter</h2>
<p>Count: {{ store.count }}</p>
<p>Double Count: {{ store.doubleCount }}</p>
<button @click="store.increment">Increment</button>
<button @click="store.decrement">Decrement</button>
<button @click="incrementBy(5)">Increment by 5</button>
</div>
</template>
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter';
const store = useCounterStore();
const incrementBy = (amount: number) => {
store.incrementBy(amount);
};
</script>
处理异步操作
// src/stores/counter.ts
import { defineStore } from 'pinia';
interface CounterState {
count: number;
}
export const useCounterStore = defineStore({
id: 'counter',
state: (): CounterState => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
incrementBy(amount: number) {
this.count += amount;
},
async incrementAsync(amount: number) {
// 模拟异步操作
return new Promise<void>((resolve) => {
setTimeout(() => {
this.incrementBy(amount);
resolve();
}, 1000);
});
}
}
});
组件中使用异步操作
<!-- src/components/CounterComponent.vue -->
<template>
<div>
<h2>Counter</h2>
<p>Count: {{ store.count }}</p>
<p>Double Count: {{ store.doubleCount }}</p>
<button @click="store.increment">Increment</button>
<button @click="store.decrement">Decrement</button>
<button @click="incrementBy(5)">Increment by 5</button>
<button @click="incrementAsync(3)">Increment by 3 (Async)</button>
</div>
</template>
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter';
const store = useCounterStore();
const incrementBy = (amount: number) => {
store.incrementBy(amount);
};
const incrementAsync = async (amount: number) => {
await store.incrementAsync(amount);
};
</script>
模块化Store
Pinia 通过 defineStore 函数实现模块化 Store,每个 Store 都是一个独立的模块。
定义用户Store
// src/stores/user.ts
import { defineStore } from 'pinia';
interface UserState {
name: string;
age: number;
}
export const useUserStore = defineStore({
id: 'user',
state: (): UserState => ({
name: 'Alice',
age: 25
}),
getters: {
isAdult: (state) => state.age >= 18
},
actions: {
updateName(newName: string) {
this.name = newName;
},
incrementAge() {
this.age++;
}
}
});
使用持久化插件
如果希望 Pinia 的状态在刷新后保持不变,可以使用 pinia-plugin-persistedstate 插件。
npm install pinia-plugin-persistedstate
配置持久化插件
// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
const app = createApp(App);
app.use(pinia);
app.mount('#app');
使用持久化插件,在需要持久化的 Store 中添加 persist 选项
// src/stores/user.ts
import { defineStore } from 'pinia';
interface UserState {
name: string;
age: number;
}
export const useUserStore = defineStore({
id: 'user',
state: (): UserState => ({
name: 'Alice',
age: 25
}),
getters: {
isAdult: (state) => state.age >= 18
},
actions: {
updateName(newName: string) {
this.name = newName;
},
incrementAge() {
this.age++;
}
},
persist: {
enabled: true
}
});