文章目录
- 安装引入
- 初始化仓库Store
- 页面使用
- state
-
- [1. 直接修改state](#1. 直接修改state)
- [2. 批量修改State的值 $patch对象形式](#2. 批量修改State的值 $patch对象形式)
- [3. 批量修改State的值 $patch函数形式](#3. 批量修改State的值 $patch函数形式)
- [4. 通过actions修改 使用方法直接在实例调用](#4. 通过actions修改 使用方法直接在实例调用)
- 解构store
- getters
- [actions 同步和异步](#actions 同步和异步)
- 常见API
-
- [reset()](#reset())
- [subscribe](#subscribe)
- [onAction](#onAction)
- pinia插件
Pinia.js 有如下特点:
- 完整的 ts 的支持;
- 足够轻量,压缩后的体积只有1kb左右;
- 去除
mutations
,只有state,getters,actions
; actions
支持同步和异步;- 代码扁平化没有模块嵌套,只有
store
的概念,store
之间可以自由使用,每一个store
都是独立的 - 无需手动添加
store
,store
一旦创建便会自动添加; - 支持
Vue3
和Vue2
安装引入
javascript
cnpm install pinia -S
javascript
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/index.ts
文件。然后在用到的页面中引入
import {useTestStore} from './store'
,注意:引入和使用是分开的
初始化仓库Store
- 创建文件
store/index.ts
- 定义仓库Store
javascript
import { defineStore } from 'pinia'
export const useTestStore = defineStore('test', {
state:()=>{
return{
current:1
}
},
getters:{
},
actions:{
}
})
- 使用defineStore定义仓库,传唯一id。变量名称命名为use...是可组合项之间的约定,以使其使用习惯。
- 唯一的id。类似于
vue2
的module
模块的功能,这样更加的方便。
- 唯一的id。类似于
- State 箭头函数 返回一个对象 在对象里面定义值
- getters类似计算属性
- actions里面可以定义同步和异步
页面使用
引入对应的store
名称useTestStore
,然后执行useTestStore()
。
javascript
<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>
<style>
</style>
state
1. 直接修改state
javascript
// 直接修改state
const editState = ()=>{
TestStore.current++
}
2. 批量修改State的值 $patch对象形式
javascript
const editState2 = ()=>{
TestStore.$patch({
current:200,
name:300
})
}
3. 批量修改State的值 $patch函数形式
函数默认state
参数,传递给 $patch() 的函数必须是同步的。
推荐使用函数形式 可以自定义修改逻辑比如if判断
javascript
const editState3 = ()=>{
TestStore.$patch((state)=>{
state.current = 300
state.name = 300
})
}
4. 通过actions修改 使用方法直接在实例调用
javascript
const editState4 = ()=>{
TestStore.setCurrent()
}
javascript
// pinia没有mutation 只有actions 同步异步都在这里处理
actions: {
// 同步
setCurrent() {
console.log('this', this)
this.current++
}
}
解构store
在
Pinia
是不允许直接解构是会失去响应性的
javascript
const Test = useTestStore()
const { current, name } = Test
console.log(current, name);
这种是不具有响应式的
要想得到响应式效果需要使用pinia
自带的storeToRefs
javascript
import { storeToRefs } from 'pinia'
const Test = useTestStore()
const { current, name } = storeToRefs(Test)
其原理跟toRefs 一样的给里面的数据包裹一层toref。
源码通过toRaw使store变回原始数据防止重复代理。循环store 通过 isRef isReactive 判断 如果是响应式对象直接拷贝一份给refs 对象 将其原始对象包裹toRef 使其变为响应式对象
getters
主要作用类似于computed 数据修饰并且有缓存
javascript
getters: {
terCurrent(): string {
return `getters:普通调用可以使用this访问属性--------${this.current}`
},
terCurrent2: (state) => {
return `getters:箭头函数无法使用this 需要使用getters默认第一个参数state访问---- ${state.current}`
},
},
普通函数形式可以使用this,箭头函数不能使用this,可以使用state参数
actions 同步和异步
同步
同步直接调用即可
javascript
const editState4 = ()=>{
TestStore.setCurrent()
}
javascript
// pinia没有mutation 只有actions 同步异步都在这里处理
actions: {
// 同步
setCurrent() {
console.log('this', this)
this.current++
}
}
异步
异步 可以结合async await 修饰
javascript
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: '4444',
isChu: true
})
}, 3000)
})
}
export const useTestStore = defineStore('test' {
state: () => ({
user: <Result>{},
name: "123"
}),
actions: {
async getLoginInfo() {
const result = await Login()
this.user = result;
}
},
})
javascript
<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>
<style>
</style>
常见API
$reset()
重置store到它的初始状态
javascript
const resetFn=()=>{
TestStore.$reset()
}
$subscribe
订阅state的改变,只要有state 的变化就会走这个函数
javascript
Test.$subscribe((args,state)=>{
console.log(args,state);
})
$onAction
订阅Actions的改变,只要有actions被调用就会走这个函数
javascript
Test.$onAction((args)=>{
console.log(args);
})
pinia插件
pinia和vuex一样,一旦刷新页面就会数据丢失。
一般会设计一个插件,将state缓存起来。
javascript
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"
}))
pinia持久化工具pinia-plugin-persist
安装
javascript
npm i pinia-plugin-persist --save
引入
javascript
main.ts
// 引入状态管理器
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
// pinia添加数据持久化插件
const pinia = createPinia()
pinia.use(piniaPluginPersist)
app.use(pinia)
ts声明文件
在根目录创建types
文件夹存放类似这种没有声明文件的情况。创建pinia-plugin-persist.d.ts
文件(ts会全局检查.d.ts文件)
javascript
declare module 'pinia-plugin-persist'
javascript
import { defineStore } from 'pinia'
export const Store = defineStore('comStore', {
// 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
// 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
// 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
state: () => {
return {
}
},
getters: {
},
actions: {
},
persist: {
enabled: true, // true 表示开启持久化保存
strategies: [
{
key: 'user', //设置缓存名称
storage: sessionStorage, //设置缓存方式
paths: ['userInfo'], //设置需要缓存的对象
},
],
},
})