Pinia.js 是新一代的状态管理器,由 Vue.js团队中成员所开发的,因此也被认为是下一代的 Vuex,即 Vuex5.x,在 Vue3.0 的项目中使用也是备受推崇。
Pinia的成功可以归功于其管理存储数据的独特功能(可扩展性、存储模块组织、状态变化分组、多存储创建等)。
Pinia.js 有如下特点:
npm install pinia --save
/**
* pinia 创建
*/
import { createPinia } from 'pinia'
const store = createPinia()
export default store
import { createApp } from 'vue'
import App from './App.vue'
//引入pinia
import store from './store'
const app = createApp(App)
app.use(store)
use开头命名
import { defineStore } from 'pinia'
export const useUsersStore = defineStore({
id: 'user', // id必填,且需要唯一
//数据仓库State 箭头函数 返回一个对象 在对象里面定义值
state: () => {
return {
name: '张三',
arr: ["名侦探柯南", "海贼王", "死神", "火影忍者"],
num: 5
}
},
//类似于computed 封装计算属性,它有缓存的功能
getters: {
getNum: (state) => state.num = state.num * 5
},
//methods 支持同步和异步 就是用来封装业务逻辑,修改 state
actions: {
getStore() {
console.log(this.name + "66666");
}
},
})
defineStore 接收两个参数:
第一个参数就是模块的名称,必须是唯一的,多个模块不能重名,Pinia 会把所有的模块都挂载到根容器上
第二个参数是一个对象
- 其中 state 用来存储全局状态,它必须是箭头函数,为了在服务端渲染的时候避免交叉请求导致的数据状态污染所以只能是函数,而必须用箭头函数则为了更好的 TS 类型推导
- getters 就是用来封装计算属性,它有缓存的功能
- actions 就是用来封装业务逻辑,修改 state,需要注意的是不能用箭头函数定义 actions,不然就会绑定外部的 this 了
<template>
<!-- 直接用 -->
{{ useStores.name }}
{{ useStores.getNum }}
<el-button type="primary" size="default" @click="handleSetState"
>点击stores里面的值</el-button
>
</template>
<script>
import { defineComponent } from "vue";
import { useUsersStore } from "@/store/modules/useUsers";
export default defineComponent({
setup() {
//调用
const useStores = useUsersStore();
//使用actions函数
useStores.getStore();
let handleSetState = () => {
//改变他state里面的值
useStores.name = "隔壁老王";
};
return {
handleSetState,
useStores,
};
},
});
</script>
state 也可以使用解构,但使用解构会使其失去响应式,这时候可以用 pinia 的 storeToRefs。
import { storeToRefs } from 'pinia'
const { name } = storeToRefs(useUsersStore())
useStores.name="王五"
但一般不建议这么做,建议通过 actions 去修改 state,action 里可以直接通过 this 访问。
import { defineStore } from 'pinia'
export const useUsersStore = defineStore({
id: 'user', // id必填,且需要唯一
state: () => {
return {
name: '张三',
arr: ["名侦探柯南", "海贼王", "死神", "火影忍者"],
num: 5
}
},
//methods 支持同步和异步
actions: {
setStore(val: string) {
this.name = val
}
},
})
-------------------------------------------------------------------
<template>
<!-- 直接用 -->
{{ useStores.name }}
<el-button type="primary" size="default" @click="handleSetState"
>点击stores里面的值</el-button
>
</template>
<script>
import { defineComponent } from "vue";
import { useUsersStore } from "@/store/modules/useUsers";
export default defineComponent({
setup() {
//调用
const useStores = useUsersStore();
let handleSetState = () => {
//使用actions函数,改变state的name值
useStores.setStore("李四");
};
return {
handleSetState,
useStores,
};
},
});
</script>
useStores.getNum
需要注意的是不能用箭头函数定义 actions,不然就会绑定外部的 this 了
actions: {
async getgood(){
//xxx是请求函数
let result = await xxxx()
return result
}
}
actions: {
async getgood(){
//xxx是请求函数
let result = await xxxx()
this.getResult(result)// 调用另一个 action 的方法
return result
},
getResult(val){
console.log(val)
}
}
//user.ts
import { useAStore } from './a'
actions: {
getData(){
useAStore.setData("哈哈哈")// 调用 a store 里的 action 方法
}
}
--------------------------------
//b.ts
export const useAStore = defineStore({
id: 'app',
actions: {
setData(data) {
console.log(data)
}
}
})
pinia也是和vuex有一个缺点,就是刷新后会丢失数据。
插件 pinia-plugin-persist 可以辅助实现数据持久化功能。
npm i pinia-plugin-persist --save
// src/store/index.ts
/**
* pinia 创建
*/
import { createPinia } from 'pinia'
//刷新数据丢失问题
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
export default store
export const useUserStore = defineStore({
id: 'user',
state: () => {
return {
name: '张三',
arr: ["名侦探柯南", "海贼王", "死神", "火影忍者"],
num: 5
}
},
// 开启数据缓存
persist: {
enabled: true
}
})
数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。
persist: {
enabled: true,
strategies: [
{
key: 'my_user',//不会以 store 的 id 作为 key,而是以my_user作为key
storage: localStorage,//sessionStorage 变成 localStorage 方式
}
]
}
默认所有 state 都会进行缓存,你可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。
export const useUserStore = defineStore({
id: 'user',
state: () => {
return {
name: '张三',
arr: ["名侦探柯南", "海贼王", "死神", "火影忍者"],
num: 5
}
},
// 开启数据缓存
persist: {
enabled: true,
strategies: [
{
storage: localStorage,
paths: ['name', 'num']
}
]
}
})
上面我们只持久化 name 和 num,并将其改为localStorage, 而 arr不会被持久化,如果其状态发送更改,页面刷新时将会丢失,重新回到初始状态,而 name 和 num 则不会。