简介
前言 全局状态管理工具
Pinia.js 有如下特点:
完整的 ts 的支持;
足够轻量,压缩后的体积只有1kb左右;
去除 mutations,只有 state,getters,actions;
actions 支持同步和异步;
代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的
无需手动添加 store,store 一旦创建便会自动添加;
支持Vue3 和 Vue2
官方文档Pinia
git 地址 https://github.com/vuejs/pinia
1.起步 安装
npm install pinia
2.引入注册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')
Vue2 使用
import { createPinia, PiniaVuePlugin } from 'pinia'
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
el: '#app',
// other options...
// ...
// note the same `pinia` instance can be used across multiple Vue apps on
// the same page
pinia,
})
初始化
创建store文件夹
在store/index.ts下
import { defineStore } from 'pinia'
import { Names } from "./namespace/index";
/**
* 参数一:唯一名称
*/
// 简单写法: export const useTestStore = defineStore('Name',{})
export const useTestStore = defineStore(Names.Test, {
state: () => {
return {
name: '李四'
}
},
//类似于computed 可以帮我们去修饰我们的值
getters: {
},
//可以操作异步 和 同步提交state
actions: {
}
})
在store/namespace/index.ts下
export const enum Names {
Test = 'TEST'
}
state使用
<!-- name -->
<template>
<div>
{{ Test.name }}
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, toRefs } from "vue";
import { useTestStore } from "./store/index"; // 引入
const Test = useTestStore(); //
</script>
<style scoped lang="less"></style>
state修改值
1.State 是允许直接修改值的 例如current++
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.current}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.current++
}
</script>
2.批量修改State的值
在他的实例上有$patch方法可以批量修改多个值
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.current}}
</div>
<div>
{{Test.age}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.$patch({
current:200,
age:300
})
}
</script>
3.批量修改函数形式
推荐使用函数形式 可以自定义修改逻辑
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.current}}
</div>
<div>
{{Test.age}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.$patch((state)=>{
state.current++;
state.age = 40
})
}
</script>
4.通过原始对象修改整个实例
$state您可以通过将store的属性设置为新对象来替换store的整个状态
缺点就是必须修改整个对象的所有属性
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.current}}
</div>
<div>
{{Test.age}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.$state = {
current:10,
age:30
}
}
</script>
5.通过actions修改
定义Actions
在actions 中直接使用this就可以指到state里面的值
import { defineStore } from 'pinia'
import { Names } from './store-naspace'
export const useTestStore = defineStore(Names.TEST, {
state:()=>{
return {
current:1,
age:30
}
},
actions:{
setCurrent () {
this.current++
}
}
})
使用方法直接在实例调用
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.current}}
</div>
<div>
{{Test.age}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.setCurrent()
}
</script>
解构store
在Pinia是不允许直接解构是会失去响应性的
const Test = useTestStore()
const { current, name } = Test
console.log(current, name);
差异对比
修改Test current 解构完之后的数据不会变
而源数据是会变的
<template>
<div>origin value {{Test.current}}</div>
<div>
pinia:{{ current }}--{{ name }}
change :
<button @click="change">change</button>
</div>
</template>
<script setup lang='ts'>
import { useTestStore } from './store'
const Test = useTestStore()
const change = () => {
Test.current++
}
const { current, name } = Test
console.log(current, name);
</script>
解决方案可以使用 storeToRefs
import { storeToRefs } from 'pinia'
const Test = useTestStore()
const { current, name } = storeToRefs(Test)
其原理跟toRefs 一样的给里面的数据包裹一层toref
源码 通过toRaw使store变回原始数据防止重复代理
循环store 通过 isRef isReactive 判断 如果是响应式对象直接拷贝一份给refs 对象 将其原始对象包裹toRef 使其变为响应式对象
action与getters使用
Actions(支持同步异步)
1.同步 直接调用即可
// store/index.ts
import { defineStore } from 'pinia'
import { Names } from './store-naspace'
export const useTestStore = defineStore(Names.TEST, {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
<template>
<div>
<button @click="Add">+</button>
<div>
{{Test.counter}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.randomizeCounter()
}
</script>
2.异步 可以结合async await 修饰
import { defineStore } from 'pinia'
import { Names } from './store-naspace'
type Result = {
name: string
isChu: boolean
}
const Login = (): Promise<Result> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: '小满',
isChu: true
})
}, 3000)
})
}
export const useTestStore = defineStore(Names.TEST, {
state: () => ({
user: <Result>{},
name: "123"
}),
actions: {
async getLoginInfo() {
const result = await Login()
this.user = result;
}
},
})
template
<template>
<div>
<button @click="Add">test</button>
<div>
{{Test.user}}
</div>
</div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
Test.getLoginInfo()
}
</script>
3.多个action互相调用getLoginInfo setName
state: () => ({
user: <Result>{},
name: "default"
}),
actions: {
async getLoginInfo() {
const result = await Login()
this.user = result;
this.setName(result.name)
},
setName (name:string) {
this.name = name;
}
},
getters
1.使用箭头函数不能使用this this指向已经改变指向undefined 修改值请用state
主要作用类似于computed 数据修饰并且有缓存
getters:{
newPrice:(state)=> `$${state.user.price}`
},
2.普通函数形式可以使用this
getters:{
newCurrent ():number {
return ++this.current
}
},
3.getters 互相调用
getters:{
newCurrent ():number | string {
return ++this.current + this.newName
},
newName ():string {
return `$-${this.name}`
}
},
API
- $ reset
重置store到他的初始状态
state: () => ({
user: <Result>{},
name: "default",
current:1
}),
Vue 例如我把值改变到了10
const change = () => {
Test.current++
}
调用$reset();
将会把state所有值 重置回 原始状态
2.订阅state的改变
类似于Vuex 的abscribe 只要有state 的变化就会走这个函数
Test.$subscribe((args,state)=>{
console.log(args,state);
})
第二个参数
如果你的组件卸载之后还想继续调用请设置第二个参数
Test.$subscribe((args,state)=>{
console.log(args,state);
},{
detached:true
})
3.订阅Actions的调用
只要有actions被调用就会走这个函数
Test.$onAction((args)=>{
console.log(args);
})
pinia 常驻
方式一:
一、通过pinia-plugin-persist插件来进行pinia的数据持久化操作
二、使用步骤
1.首先下载安装插件
代码如下(示例):
npm i pinia-plugin-persist --save --include=dev
// 或者使用 yarn 安装
yarn add pinia-plugin-persist
2.在main.ts/main.js中引入
代码如下(示例):
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from "pinia"
// 数据持久化插件
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
const app = createApp(App)
app.use(pinia)
app.mount('#app')
- 具体模块中的使用看下面的代码
import { defineStore } from "pinia";
export const useHome = defineStore('home', {
state: ()=>{
return {
studyCourse: 0,
num: 1,
msg: '测试'
}
},
persist: {
enabled: true, // 开启存储
// **strategies: 指定存储位置以及存储的变量都有哪些,该属性可以不写,不写的话默认是存储到sessionStorage里边,默认存储state里边的所有数据**
strategies:[
{ storage: localStorage, paths: ['studyCourse', 'num']}
// storage 存储到哪里 sessionStorage/localStorage
// paths是一个数组,要存储缓存的变量,当然也可以写多个
// paths如果不写就默认存储state里边的所有数据,如果写了就存储指定的变量
]
},
actions: {
addStudyCourse () {
this.studyCourse++
}
},
})
方式二:
const __piniaKey = '__PINIAKEY__'
//定义兜底变量
type Options = {
key?:string
}
//定义入参类型
//将数据存在本地
const setStorage = (key: string, value: any): void => {
localStorage.setItem(key, JSON.stringify(value))
}
//存缓存中读取
const getStorage = (key: string) => {
return (localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : {})
}
//利用函数柯丽华接受用户入参
const piniaPlugin = (options: Options) => {
//将函数返回给pinia 让pinia 调用 注入 context
return (context: PiniaPluginContext) => {
const { store } = context;
const data = getStorage(`${options?.key ?? __piniaKey}-${store.$id}`)
store.$subscribe(() => {
setStorage(`${options?.key ?? __piniaKey}-${store.$id}`, toRaw(store.$state));
})
//返回值覆盖pinia 原始值
return {
...data
}
}
}
//初始化pinia
const pinia = createPinia()
//注册pinia 插件
pinia.use(piniaPlugin({
key: "pinia"
}))
原文链接:https://blog.csdn.net/qq1195566313/article/details/123431769