Pinia是一个全新的Vue状态管理库,由 Vue.js团队成员开发。
对比vuex
- yarn add pinia
- # 或者使用 npm
- npm install pinia
- 复制代码
首先需要在main.ts引入
- import { createApp } from 'vue'
- import { createPinia } from 'pinia'
-
- const app = createApp(App)
- app.use(createPinia())
- app.mount('#app')
- 复制代码
defineStore函数用来定义一个状态,返回一个使用状态的函数。
我们把状态定义在在/src/store/index.ts文件内,当然也可以定义在其他文件内,并且defineStore可以定义多个状态集合
- import { defineStore } from 'pinia'
-
- // useStore 可以是 useUser、useCart 之类的任何东西
- export const useCountStore = defineStore('count', {
- // state:定义状态
- state: ()=>({
- count: 0
- }),
- // getters:与vuex一致,类似于computer
- getters: {
- dbCount:(state)=>state.count*2
- },
- // actions:与vuex一致,用于修改状态
- actions: {
- countPlus() {
- this.count++
- }
-
- }
- })
- 复制代码
defineStore第一个参数是应用程序中 store 的唯一 id,第二个参数是一个选项的对象,与Vuex类似不过没有Mutation字段
调用useStore方法,返回store实例
- <template>
- <div class='home'>
- <div>{{countStore.count}}</div>
- <button @click="countPlus">count++</button>
- </div>
- </template>
-
- <script setup lang="ts">
- import {useCountStore} from "./useStore";
-
- const countStore = useCountStore()
- // 通过countStore可以直接访问到state、getters、actions中定义的状态和方法
- countStore.count
- countStore.dbCount
- countStore.countPlus()
-
-
- function countPlus(){
- // 可以直接修改 count
- countStore.count++
- // 也可以通过$state替换整个状态
- countStore.$state = {count: countStore.count+1}
- // 使用$patch修改状态
- countStore.$patch({
- count: countStore.count+1
- })
- // 调用actions中的方法
- countStore.countPlus()
- }
-
- </script>
- 复制代码
定义状态
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- })
- })
- 复制代码
访问/修改state
- const countStore = useCountStore()
- // 访问
- countStore.count
- countStore.$state.count
-
- // 可以直接修改 count
- countStore.count++
- // 也可以通过$state替换整个状态
- countStore.$state = {count: countStore.count+1}
- // 使用$patch修改状态
- countStore.$patch({
- count: countStore.count+1
- })
- 复制代码
与计算属性一样,您可以组合多个 getter。 通过 this 访问任何其他 getter。
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- }),
- getters: {
- // 回调函数的参数为state
- dbCount:(state)=>state.count*2,
- // this为该store实例,可以访问到其他的getters
- doubleCountPlusOne() {
- return this.doubleCount + 1
- }
- }
- })
- 复制代码
getter传递参数
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- }),
- getters: {
- // getters返回一个函数,并接受一个参数
- countFormat: (state) => {
- return (fmt) => state.count+fmt
- },
- }
- })
- 复制代码
访问其他 Store 的 getter
- export const useUserStore = defineStore('user', {
- state: ()=>({
- name: 'yxx'
- }),
- getters: {
- countFormat: (state) => {
- return (fmt) => state.count+fmt
- },
- }
- })
-
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- }),
- getters: {
- // getters返回一个函数,并接受一个参数
- userCount: (state) => {
- const userStore = useUserStore()
- return `${userStore.name}写了${state.count}个bug`
- },
- }
- })
- 复制代码
访问getters
- const countStore = useCountStore()
-
- countStore.dbCount
- countStore.doubleCountPlusOne
- countStore.countFormat('个')
- countStore.userCount
-
- 复制代码
Actions 相当于组件中的 methods。 可以使用 defineStore() 中的 actions 属性定义
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- }),
- actions: {
- // 与getters一样,可以通过this访问该store实例
- countPlus() {
- this.count++
- },
- // actions 可以是异步的
- async asyncCountPlus(){
- const res = await axios.get('xxxx')
- this.count = res.data
- }
-
- }
- })
- 复制代码
访问其他 Store 的 actions
- export const useUserStore = defineStore('user', {
- state: ()=>({
- name: 'yxx'
- }),
- actions: {
- setName: () => {
- this.name = 'yxx'
- },
- }
- })
-
- export const useCountStore = defineStore('count', {
- state: ()=>({
- count: 0
- }),
- actions: {
- setUserName: (state) => {
- const userStore = useUserStore()
- userStore.setName()
- },
- }
- })
- 复制代码
访问actions
- const countStore = useCountStore()
-
- countStore.countPlus()
- countStore.asyncCountPlus()
- countStore.setUserName()
- 复制代码
defineStore第二个参数也可以接收一个函数,函数可以返回一个响应式的变量和它的计算属性、修改方法等
- import {defineStore} from "pinia";
- import {ref, computed} from "vue";
-
- export const useCountStore = defineStore('count', ()=>{
- const count = ref(0)
- const dbCount = computed(()=>count.value*2)
- const userInfo = reactive({
- name: 'yxx',
- age: 12
- })
- function countPlus(){
- count.value++
- }
-
- return {count, dbCount, userInfo, countPlus}
- })
- 复制代码
这种方法与第一种方法定义状态所返回的实例没有区别,访问属性和方法的方式也没有变化
使用ref或reactive定义的响应式变量等同于state中的状态
使用computed定义的计算属性等同于getters中的内容
return出来的其他方法等同于actions中的方法
- <template>
- <div class="">
- <div>count: {{countStore.count}}</div>
- <div>dbCount: {{countStore.dbCount}}</div>
- <button @click="butClick">count++</button>
- </div>
- </template>
-
- <script setup lang="ts">
- import {useCountStore} from "./useStore";
-
- const countStore = useCountStore()
- // 访问状态
- countStore.count
- // 或者
- countStore.$state.count
- // 访问计算属性
- countStore.dbCount
-
- function butClick(){
- // 访问方法
- countStore.countPlus()
- }
- </script>
- 复制代码
state、getters、actions中定义的状态和方法可以直接被store实例访问,除了这些还有以下属性/方法
$id为该store实例的ID,也就是defineStore的第一个参数
- const countStore = useCountStore()
- countStore.id // => 'count'
- 复制代码
使用$state可以访问到全部状态,并且可以直接整个替换整个状态
- const countStore = useCountStore()
- countStore.$state = {count: countStore.count+1}
- 复制代码
$patch用来修改状态,可以直接传递个对象,也可以传递一个回调函数
- const countStore = useCountStore()
-
- // 传递对象
- countStore.$patch({
- count: countStore.count+1
- })
- // 传递函数,函数第一个参数为state
- countStore.$patch(state=>{
- state.count++
- })
- 复制代码
$reset用来重置状态,调用它所有的状态都会重置为初始值
- const countStore = useCountStore()
-
- countStore.$reset()
- 复制代码
$subscribe订阅状态
第一个参数接受一个回调函数,当状态被修改时会调用回调函数
第二个参数接受一个对象{ detached: true },detached默认false,设为true时当组件销毁时订阅不会取消
- const countStore = useCountStore()
-
- countStore.$subscribe((mutation, state) => {
- console.log('mutation',mutation)
- // 修改数据的方式
- // 'direct': 通过countStore.count直接修改
- // 'patch object' 使用countStore.$patch({})修改的数据
- // 'patch function' 使用countStore.$patch((state)=>void)修改的数据
- mutation.type
- // 与 cartStore.$id 相同
- mutation.storeId // 'cart'
- // 仅适用于 mutation.type === 'patch object'
- mutation.payload // 传递给$patch的对象
- },{ detached: true })
- 复制代码
$onAction订阅Action,接受一个回调函数,当Action被调用时会调用回调函数
- const countStore = useCountStore()
-
- countStore.$onAction(
- ({
- name, // action 的名字
- store, // store 实例
- args, // 调用这个 action 的参数
- after, // 在这个 action 执行完毕之后,执行这个函数
- onError, // 在这个 action 抛出异常的时候,执行这个函数
- })=>{
- console.log(name,store,args,after,onError)
- onError(()=>{
- console.log('action 抛出异常')
- })
- })
- 复制代码
类似于toRefs,用于结构一个响应式对象,
store 是一个用reactive 包裹的对象,这意味着不需要在getter 之后写.value,但是,就像setup 中的props 一样,我们不能对其进行解构:
- const countStore = useCountStore()
- // 这不起作用,因为它会破坏响应式
- // 这和从 props 解构是一样的
- const { count, dbCount } = countStore
- 复制代码
为了从 Store 中提取属性同时保持其响应式,您需要使用storeToRefs()。 它将为任何响应式属性创建 refs。 当您仅使用 store 中的状态但不调用任何操作时,这很有用:
- const countStore = useCountStore()
-
- const { count, dbCount } = storeToRefs(countStore)
- // (试了一下,用toRefs也能实现同样的效果)
- const { count, dbCount } = toRefs(countStore)
链接:https://juejin.cn/post/7146009047311843342