特点:
- 完整的 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 | |
}, |