# 一、特点
- 完整的 ts 支持
- 三大核心:state(存储的值),getters(计算属性),actions 也可支持同步(改变值的方法,支持同步和异步)
- 与 vuex 相比,去除了 mutations(actions 也可支持同步)和 modules(只有 store 之间的互相引用)
# 二、安装
| yarn add pinia | 
# 三、使用
# 1. 创建 pinia 实例
新建 store/index.ts(src 目录下新建 store 文件夹,并创建 index.ts 文件)
| import { createPinia } from 'pinia'; | |
| const store = createPinia(); | |
| export default store; | 
# 2. 在 main.js 中引用
| import { createApp } from 'vue'; | |
| import App from './App.vue'; | |
| import store from './store'; | |
| const app = createApp(App); | |
| app.use(store); | |
| app.mount('#app'); | 
# 3. 创建 store
新建 store/user.ts
| import { defineStore } from 'pinia'; | |
| //defineStore 第一个参数是 id,必需且值唯一 | |
| export const useUserStore = defineStore('user', { | |
|   //state 返回一个函数,防止作用域污染 | |
| state: () => { | |
| return { | |
| userInfo: { | |
| name: 'zhangsan', | |
| age: 23, | |
| }, | |
| token: 'S1', | |
| }; | |
| }, | |
| getters: { | |
| newName: (state) => state.userInfo.name + 'vip', | |
| }, | |
| actions: { | |
|     // 更新整个对象 | |
| updateUserInfo(userInfo: { name: string; age: number }) { | |
| this.userInfo = userInfo; | |
| }, | |
|     // 更新对象中某个属性 | |
| updateAge(age: number) { | |
| this.userInfo.age = age; | |
| }, | |
|     // 更新基础数据类型 | |
| updateToken(token: string) { | |
| this.token = token; | |
| }, | |
| }, | |
| }); | 
# 4. 使用 store
store 是一个用 reactive 包装的对象,直接解构读取 state 会失去响应式,因此需要 storeToRefs,它将为每一个响应式属性创建引用;需通过 .value 读取解构出来的值
| <template> | |
| <div> | |
| <div>姓名:<!--swig0--> 年龄:<!--swig1--></div> | |
| <div>token:<!--swig2--></div> | |
| <div>getter值:<!--swig3--></div> | |
| <button @click="handleUser">更新用户</button> | |
| <button @click="handleAge">更新年龄</button> | |
| <button @click="handleToken">更新token</button> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { storeToRefs } from 'pinia'; | |
| import { useUserStore } from '@/store/user'; // 路径别名,引入 store | |
| const userStore = useUserStore(); | |
| //storeToRefs 会跳过所有的 action 属性 | |
| const { userInfo, token, newName } = storeToRefs(userStore); | |
| //action 属性直接解构 | |
| const { updateUserInfo, updateAge, updateToken } = userStore; | |
| const handleUser = () => { | |
| updateUserInfo({ name: 'lisi', age: 24 }); | |
| }; | |
| const handleAge = () => { | |
|   //userInfo 是一个 ref 响应式引用,需通过.value 取值 | |
| updateAge(userInfo.value.age + 1); | |
| }; | |
| const handleToken = () => { | |
| updateToken('23234'); | |
| }; | |
| </script> | 
# 5. 异步 actions
除了上面展示的同步 action,action 也可以是异步的
新建 store/list.ts
| import { defineStore } from 'pinia'; | |
| const getData = () => { | |
| return new Promise<number>((resolve) => { | |
| setTimeout(() => { | |
| resolve(Math.random() * 100); | |
| }, 200); | |
| }); | |
| }; | |
| export const useListStore = defineStore('list', { | |
| state: () => { | |
| return { | |
| list: [] as number[], | |
| }; | |
| }, | |
| actions: { | |
| async updateList() { | |
| try { | |
| const data = await getData(); | |
| this.list.push(data); | |
| } catch { | |
|         /* empty */ | |
|       } | |
| }, | |
| }, | |
| }); | 
# 6. store 的相互引用
每个 store 可看做一个 hook。相互引用即调用不同 hook
新建 store/userSex.ts
| import { defineStore } from 'pinia'; | |
| import { useUserStore } from './user'; | |
| enum Sex { | |
| man = '男人', | |
| woman = '女人', | |
| } | |
| export const userSexStore = defineStore('user2', { | |
| state: () => { | |
| return { | |
| sex: Sex.man, | |
| }; | |
| }, | |
| actions: { | |
| updateSex() { | |
| const userStore = useUserStore(); // 引用其他 store | |
| if (userStore.userInfo.name !== 'zhangsan') this.sex = Sex.woman; | |
| }, | |
| }, | |
| }); | 
# 7. 路由钩子中使用 store
使用 store 的前提是保证 pinia 已被注册
| import { useUserStore } from '@/store/user'; | |
| router.beforeEach((to, from) => { | |
|   // 这样做是可行的,因为路由器是在其被安装之后开始导航的, | |
|   // 而此时 Pinia 也已经被安装。 | |
| const userStore = useUserStore(); | |
| if (!userStore.token && to.path !== "/login") { | |
| return "/login"; | |
|   } | |
| }); | 
# 四、数据持久化
# 1. 安装插件
| yarn add pinia-plugin-persistedstate | 
# 2. 引用插件
修改 store/index.ts
| import { createPinia } from 'pinia'; | |
| import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; | |
| const store = createPinia(); | |
| store.use(piniaPluginPersistedstate); // 使用持久化插件 | |
| export default store; | 
# 3. 在 store 模块中启用持久化
在 user.ts 中启用:添加 persist 配置项
| import { defineStore } from 'pinia' | |
| export const useUserStore = defineStore('user', { | |
| state: () => ({ | |
|     ... | |
| }), | |
| getters: { ... }, | |
| actions: { ... }, | |
|   // 开始数据持久化 | |
| persist: true, | |
| }) | 
当更新 state 值时,会默认存储到 localStorage 中
# 4. 修改 key 与存储位置
默认存储到 localStorage 的 key 值就是 store 模块 id 值。可以修改 key 值和存储位置
| // 将 persist: true, 改为 | |
| persist: { | |
| key: 'storekey', // 修改存储的键名,默认为当前 Store 的 id | |
| storage: window.sessionStorage, // 存储位置修改为 sessionStorage | |
| }, | 
# 5. 自定义要持久化的字段
默认会将 store 中的所有字段都缓存,可以通过 paths 点符号路径数组指定要缓存的字段
| persist: { | |
| paths: ['userInfo.name'], // 存储 userInfo 的 name | |
| }, | 
