Pinia使用
- Pinia简介
- 安装Pinia
- 存储数据和读取数据
- State
- 读取数据
- 重置 state
- 修改state值
- storeToRefs
- 监听state
- Getter
- 读取数据
- Action
Pinia简介
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
安装Pinia
yarn add pinia
# 或者使用 npm
npm install pinia
创建一个 pinia 实例 (根 store) 并将其传递给应用:
typescript">import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const pinia = createPinia()
const app = createApp(App)app.use(pinia)
app.mount('#app')
显示下图证明使用pinia成功
存储数据和读取数据
Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的 data、 computed 和 methods。
Store 是用 defineStore() 定义的,它的第一个参数要求是一个独一无二的名字:
typescript">import { defineStore } from 'pinia'// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {// 其他配置...
})
有两种写法
选项式Store
typescript">export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),getters: {double: (state) => state.count * 2,},actions: {increment() {this.count++},},
})
组合式Store
typescript">export const useCounterStore = defineStore('counter', () => {const count = ref(0)const doubleCount = computed(() => count.value * 2)function increment() {count.value++}return { count, doubleCount, increment }
})
在 Setup Store 中:
- ref() 就是 state 属性
- computed() 就是 getters
- function() 就是 actions
State
在 Pinia 中,state 被定义为一个返回初始状态的函数
typescript">import { defineStore } from 'pinia'export const useUserStore = defineStore("user",{state(){return{username : "xiaoc", //属性都将自动推断出它们的类型age : 25,poclist:[{ id: "dasdasdad01", title: "禅道 12.4.2 后台任意文件上传漏洞", content: "禅道 <= 12.4.2版本" },{ id: "dasdasdad02", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad03", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad04", title: "HiKVISION 综合安防管理平台 report 任意文件上传漏洞", content: "HiKVISION 综合安防管理平台" }]}}
})
读取数据
默认情况下,你可以通过 store 实例访问 state,直接对其进行读写。
typescript">import {useUserStore} from '@/store/user'const userStore =useUserStore()
console.log(userStore)
重置 state
使用选项式 API 时,你可以通过调用 store 的 $reset() 方法将 state 重置为初始值。
typescript">userStore.$reset()
console.log(userStore)
在 Setup Stores 中,您需要创建自己的 $reset() 方法:
typescript">export const useCounterStore = defineStore('counter', () => {const count = ref(0)function $reset() {count.value = 0}return { count, $reset }
})
修改state值
直接修改
typescript">userStore.username = "xiaohei"
批量修改
typescript">const userStore =useUserStore()
userStore.$patch({username:'xiaoc123456',age:100,
})
借助action
修改(action
中可以编写一些业务逻辑)
typescript">import { defineStore } from 'pinia'export const useUserStore = defineStore("user",{state(){return{username : "xiaoc", //属性都将自动推断出它们的类型age : 25,poclist:[{ id: "dasdasdad01", title: "禅道 12.4.2 后台任意文件上传漏洞", content: "禅道 <= 12.4.2版本" },{ id: "dasdasdad02", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad03", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad04", title: "HiKVISION 综合安防管理平台 report 任意文件上传漏洞", content: "HiKVISION 综合安防管理平台" }]}},actions:{updateusername(){this.username ="这是通过action修改的名字"}}
组件中调用action
即可
typescript">// 使用countStore
const countStore = useCountStore()// 调用对应action
countStore.incrementOdd(n.value)
storeToRefs
通过解构获取数据,会提示获取到的数据是常数,而不是响应式数据
typescript">const {username,age,poclist} =userStorefunction changeUsername(){ager += 1
}
需要使用storeToRefs
typescript">const {username,age,poclist} =storeToRefs(userStore)function changeUsername(){age.value += 1
}
监听state
类似于 Vuex 的 subscribe 方法,你可以通过 store 的 $subscribe() 方法侦听 state 及其变化。比起普通的 watch(),使用 $subscribe() 的好处是 subscriptions 在 patch 后只触发一次 (例如,当使用上面的函数版本时)。
typescript">cartStore.$subscribe((mutation, state) => {// import { MutationType } from 'pinia'mutation.type // 'direct' | 'patch object' | 'patch function'// 和 cartStore.$id 一样mutation.storeId // 'cart'// 只有 mutation.type === 'patch object'的情况下才可用mutation.payload // 传递给 cartStore.$patch() 的补丁对象。// 每当状态发生变化时,将整个 state 持久化到本地存储。localStorage.setItem('cart', JSON.stringify(state))
})
typescript">userStore.$subscribe((mutation,state)=>{console.log(mutation,state);})
存储本地会话
typescript">function changename(){userStore.updateusername()localStorage.setItem('poclist',JSON.stringify(userStore.poclist))
}
Getter
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数:
typescript">import { defineStore } from 'pinia'export const useUserStore = defineStore("user",{state(){return{username : "xiaoc", //属性都将自动推断出它们的类型age : 25,poclist:[{ id: "dasdasdad01", title: "禅道 12.4.2 后台任意文件上传漏洞", content: "禅道 <= 12.4.2版本" },{ id: "dasdasdad02", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad03", title: "Rails sprockets 任意文件读取漏洞", content: "Sprockets < 3.7.1" },{ id: "dasdasdad04", title: "HiKVISION 综合安防管理平台 report 任意文件上传漏洞", content: "HiKVISION 综合安防管理平台" }]}},getters:{doubleAge:(state)=>state.age*2},actions:{updateusername(){this.username ="这是通过action修改的名字"}}
})
使用其他 getter
我们也可以通过 this 访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。这是为了避免 TypeScript 的已知缺陷,不过这不影响用箭头函数定义的 getter,也不会影响不使用 this 的 getter。
读取数据
可以直接访问 store 实例上的 getter
typescript">getters:{doubleAge:(state)=>state.age*2,changeDoubleAge():number{return this.doubleAge*4}
},
Action
Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。
typescript">export const useCounterStore = defineStore('main', {state: () => ({count: 0,}),actions: {increment() {this.count++},randomizeCounter() {this.count = Math.round(100 * Math.random())},},
})