pinia学习

01 - pinia介绍

pinia图.png

Pinia.js 有如下特点:

  • 完整的 ts 的支持;

  • 足够轻量,压缩后的体积只有1kb左右;

  • 去除 mutations,只有 state,getters,actions;

  • actions 支持同步和异步;

  • 代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的

  • 无需手动添加 store,store 一旦创建便会自动添加;

  • 支持Vue3 和 Vue2

起步安装

npm install pinia

引入注册Vue3

import { createApp } from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'

const store = createPinia()
let app = createApp(App)


app.use(store)

app.mount('#app')

store hook创建

import { defineStore } from "pinia";
import {Names} from "./store-name"

export const useTestStore = defineStore(Names.TEST, {
state: () => {
return {
name:'小潘',
age:22
};
},
// computed 修饰一些属性
getters:{

},
// methods 可以做同步、异步都可以提交state
actions:{

}
});

store hook 使用

<template>
<div>
{{ testStore.name}}=={{ testStore.age }}
</div>
</template>


<script setup lang="ts">
import {useTestStore} from "./store"

const testStore = useTestStore()
</script>

<style scoped>

</style>

02 - state使用的方式

第一种方式:直接使用

testStore.age = 19

第二种方式:通过$patch,(可以传值一个或多个)

testStore.$patch({
age:19,
name:"xiaopan"
})

第三种方式:通过$patch,(可以传函数)(推荐使用)

testStore.$patch((state)=>{
// 可以进行逻辑处理
state.age = 19
state.name = "xiaopan"
})

第四种方式:通过$state,(只能传全部)

testStore.$state = {
age:19,
name:"xiaopan"
}

第五种方式:通过action进行处理逻辑

// app.vue
testStore.updateAge(20)
// index.ts
actions:{
updateAge(age:number){
this.age = age
}
}

03 - 解构操作导致响应式问题

错误示范:

<template>
<div>
{{ testStore.name}}=={{ testStore.age }}
<button @click="handleClick">改变</button>
</div>
</template>


<script setup lang="ts">
import {useTestStore} from "./store"
const testStore = useTestStore()

let {name,age} = testStore
const handleClick = ()=>{
// 这样会导致响应式丢失
name = 'xiaopan'
age = 18
}
</script>

<style scoped>

</style>

使用storeToRefs解决响应式丢失问题

使用storeToRefs将store中的状态变成Ref响应式进行操作的,这样就相当重新绑定了响应式。

<template>
<div>
{{ testStore.name}}=={{ testStore.age }}
<button @click="handleClick">改变</button>
</div>
</template>


<script setup lang="ts">
import {useTestStore} from "./store"
import {storeToRefs} from "pinia"
const testStore = useTestStore()

let {name,age} = storeToRefs(testStore)
const handleClick = ()=>{
name.value = 'xiaopan'
age.value = 18
}
</script>

<style scoped>

</style>

04 - getters 和 actions 使用

// app.vue

<template>
<div>
<div>action(异步):{{ user.name }} -- {{ user.age }}</div>
<hr>
<div>getter:{{ getUser.name }} === {{ getUser.age }}</div>
<hr>
<button @click="handleClick">点我更新</button>
</div>
</template>


<script setup lang="ts">
import {useTestStore} from "./store"
import {storeToRefs} from "pinia"
const testStore = useTestStore()
const {user,getUser} = storeToRefs(testStore)

const handleClick = ()=>{
testStore.aysncUpdateAge()
}
</script>

<style scoped>

</style>

// index.ts

import { defineStore } from "pinia";
import {Names} from "./store-name"

interface User{
name:string
age:number
}
const user = {
name:'张三',
age:18
}

const ProUSer = ():Promise<User>=>{
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(user)
},2000)
})
}


export const useTestStore = defineStore(Names.TEST, {
state: () => {
return {
user:{} as User
};
},
// computed 修饰一些属性
getters:{
getUser():User{
return this.user
}
},
// methods 可以做同步、异步都可以提交state
actions:{
//异步
async aysncUpdateAge(){
this.user = await ProUSer()
}
}
});

05 - 实例API

$reset:重置store到他的初始状态

testStore.$reset()

$subscribe:类似于Vuex 的abscribe 只要有state 的变化就会走这个函数

Test.$subscribe((args,state)=>{
console.log(args,state);
})

$onAction:只要有actions被调用就会走这个函数

testStore.$onAction((args)=>{
console.log(args);
})
pinia中$onAciton的API .png

06 - pinia持久化插件编写

// 现在main.ts创建一个pinia插件
import PiniaPlugin from "./store/plugins"
const store = createPinia()
store.use(piniaPlugin({key:'xiaopan'}))

//在plugins.ts编写插件

// 引入插件context上下文类型
import {PiniaPluginContext} from "pinia"
// 使用toRaw将响应式编程普通对象
import { toRaw } from "vue";

// 定义持久化名称
const _PLUGINKEY_ = "_PLUGINKEY_"

// 定义传参的key类型
interface OPtions {
key?: string;
}
// 定义获取持久化数据
const getValue = (key:string)=>{
return (localStorage.getItem(key)?JSON.parse(localStorage.getItem(key) as string):{})
}
// 定义设置持久化数据
const setValue = (key:string,value:any)=>{
localStorage.setItem(key,JSON.stringify(value));
}

// 使用柯里化函数和闭包进行传参操作
const piniaPlugin = (options: OPtions) => {
// 插件页面加载就执行
return (context:PiniaPluginContext) => {
// 获取store数据
const {store} = context
// 获取持久化数据
let data = getValue(`${options.key?options.key+store.$id:_PLUGINKEY_ + store.$id}`)
// subscribe数据改变时,触发
context.store.$subscribe(()=>{
// 设置持久化数据
setValue(`${options.key?options.key+store.$id:_PLUGINKEY_ + store.$id}`,toRaw(store.$state))
})
// 将store返回出去
return {
// 将store数据返回出去
...data,
};
};
};

export default piniaPlugin;