Vue3中Pinia的使用

779 阅读2分钟

Pinan特点

  • 支持TS
  • 轻量,压缩后的体积只有1Kb左右
  • 去除mutations,只有state,getters,actions
  • actions支持同步和异步
  • 支持Vue2和Vue3

安装

npm install pinia

引用(main.ts)

import { createPinia } from "pinia"        //vue3引入方式
import { PiniaVuePlugin } from "pinia"     //vue2引入方式
//调用
const store = createPinia()
//注册
app.use(store)

使用(src/store/index.ts)

//引入pinia
import { defineStore } from "pinia"
//导入枚举
import { Names } from './store-name'

//导出
//注意:第一个值为id(唯一值,命名空间)
//state为箭头函数并且返回一个对象
export const useTestStore = defineStore(Names.TEST,{
    state:()=>{
        return {
            count: 1,
            name: "栗子"
        }
    },
    //类似computed
    getters: {
    
    },
    //类似methods 可做同步异步,提交state
    actions: {
        //修改state的值
        setCount(num: number){
             this.count = num
        }
    }
})
目录:src/store/store-name.ts
//导出枚举
export const enum Names {
    TEST = 'TEST'
}

在页面中使用(App.vue)

<template>
    <div>{{ Test.count }}</div>
    <div>{{ Test.name }}</div>
    <button @click="change">修改state的值</button>
</template>

//引入
import { useTestStore } from "./store"
const Test = useTestStore()

state详解(5种方式修改state的值)

  1. 直接修改state的值
const change = ()=>{
    Test.count++
}
  1. $patch(可批量修改)---对象
const change = ()=>{
    Test.$patch({
        count: 666,
        name: "小栗子"
    })
}
  1. $patch(可先处逻辑后修改值)---函数
const change = ()=>{
    Test.$patch((state)=>{
        //可先处理需要的逻辑之后在修改值
        state.count = 1314
        state.name = "追光的栗子"
    })
}
  1. $state(要修改必须覆盖整个对象)
const change = ()=>{
    Test.$state = {
        count: 333,
        name: "炒栗子"
    }
}
  1. 借助action去修改
const change = ()=>{
   //调用actions中修改state的方法,可传参
   Test.setCount(9999)
}

解构store

//引入
import { useTestStore } from "./store"
import { storeToRefs } from "pinia"    //storeToRefs函数解决pinia解构后失去响应式的问题
const Test = useTestStore()

//解构store中的count和name值
//注意:pinia解构不具有响应式
const { count,name } = storeToRefs(Test)
const change = ()=>{
   count.value++
}

actions详解

  • 可以进行同步或异步操作
  • actions中两个方法也可以相互调用
目录:src/store/index.ts
//定义一个数据类型
type User = {
    name: string,
    age: number
}
//定义数据
let result: User = {
    name: "栗子",
    age: 18
}

//模拟异步写法
//返回值为Promise,接收泛型User
const getList = ():Promise<User> =>{
    return new Promise((resolve)=>{
        setTimeout(()=>{
            resolve({
                name: "栗子",
                age: 18 
            })
        },3000)
    })
}

export const useTestStore = defineStore(Names.TEST,{
    state:()=>{
        return{
            user: <User>{},
            user2: "",
            name: "栗子"
        }
    }
    actions: {
        //同步操作
        setUser(){
           this.user =  result
        },
        //异步操作
        async getSetList(){
            const res = await getList()
            this.user2 = res
            //调用action中的方法
            this.setName("追光的栗子")
        },
        setName(name: string){
            this.name = name
        }
    }
})

在页面中使用(App.vue)

<template>
    <div>{{ Test.user }}</div>
    <div>{{ Test.user2 }}</div>
    <button @click="change">change</button>
</template>

//引入
import { useTestStore } from "./store"
const Test = useTestStore()

const change = ()=>{
    //调用store下action中的方法(同步)
    Test.setUser()
    //调用store下action中的方法(异步)
    Test.getSetList()
}

getters详解

  • 有缓存
export const useTestStore = defineStore(Names.TEST,{
    state:()=>{
        return{
          name: "栗子",
          age: 18
        }
    },
    getters:{
      filueName(): string {
          return `${this.name}----${this.getAge}`
      }  
      //也可以相互调用
      getAge(): number {
          return `${this.age}`
      }
    }
})

在页面中使用(App.vue)

<template>
    <div>{{ Test.filueName }}</div>
</template>

//引入
import { useTestStore } from "./store"
const Test = useTestStore()

Pinia中的API

  1. $reset(重置state的值到初始状态)
<template> 
    <button @click="reset">使用$reset</button> 
</template>

//引入
import { useTestStore } from "./store"
const Test = useTestStore()
const reset = ()=>{
    //恢复state的初始值
    Test.$reset()
}
  1. $subscribe(只要state中的值发生变化都会触发这个函数)
//引入
import { useTestStore } from "./store"
const Test = useTestStore()

//参数一:args里面存入新值、旧值等参数
//参数二: {detached: true}  同下方true代表意义相同
Test.$subscribe((args,state)=>{
    
},{
    detached: true,
    deep: true,
    flush: "post"
})
  1. $onAction(调用action中的方法触发)
//引入
import { useTestStore } from "./store"
const Test = useTestStore()

//参数一:args参数中有after,onError,store,arge(代表传的参数)等
//参数二: true 代表意义 如果组件被销毁了,还想监听$onAction,需要添加true
Test.$onAction((args)=>{
    //在所有事件之后执行
    args.after(()=>{
        
    })
},true)

Pinia插件的使用

  • 问题:页面刷新数据会丢失
  • 解决:封装插件维持数据持久化
//main.ts
//引入pinia
import { createPinia, PiniaPluginContext } from "pinia" 

//定义传来key的类型
type Options = {
    key?: string
}
//设置默认的key
const _piniaKey: string = "栗子"

//定义存值的函数
const setStorage = (key: string,value: any)=>{
    //存进缓存  字符串
    localStorage.setItem(key,JSON.stringify(value))
}

//定义取值的函数
const getStorage = (key: string)=>{
    return localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string : {}
}

//定义插件
//options用来接收用户传来的值
const piniaPlugin = (options: Options)=>{
    //此函数用来接收pinia的返回值
   return (context: PiniaPluginContext)=>{   
        //解构store
        const { store } = context
        //先获取数据
        //注意:store.$id为上方定义枚举的id值,此时为TEST
        const data = getStorage(`${options?.key ?? _piniaKey}-${store.$id}`)
        store.$subscribe(()=>{
            //存数据
            //使用toRaw(),把存的值转化为原始对象
            setStorage(`${options?.key ?? _piniaKey}-${store.$id}`,toRaw(store.$state))
        })
        //返回给store
        return {
            ...data
        }
   }
}


//调用 
const store = createPinia() 

//注册使用pinia插件
store.use(piniaPlugin({
    //设置key值
    key: "pinia"
}))

//注册store
app.use(store)