一、特点
- 完整的 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>姓名:{{ userInfo.name }} 年龄:{{ userInfo.age }}</div>
<div>token:{{ token }}</div>
<div>getter值:{{ newName }}</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
},