pinia是什么
-
设计目标: 一个拥有组合式API的Vue状态管理器
-
使用优点:
2.1 Devtool支持
2.2 热更新
2.3 插件扩展
2.4 TS自动补全
2.5 服务端渲染
使用前准备
- 安装
npm install pinia
# vue<=2.7时需要继续安装组合式api包
npm install @vue/composition-api
- 应用引入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from 'app.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia).mount('#app')
基础操作
- 定义store
import { defineStore } from 'pinia'
// 组合式函数风格, learn为store的id, useLearnStore为定义Store返回的函数名
export const useLearnStore = defineStore('learn', { /*配置项*/ })
1.1 选项式配置方式
/** 配置项 */
{
state: () => ({id: 0}),
getters: {
getId: state => state.id,
},
actions: {
addId() {
this.id++
},
},
}
1.2 组合式配置方式
/** 配置项 */
() => {
const id = ref(0)
const getId = () => id.value // TODO: 判断是否带有响应式 -> 不具备响应式
const getId = computed(()=>id) // 响应式的写法
const addId = () => id.value++
return { id, getId, addId }
- 使用Store
2.1 setup中使用
<script setup>
import { useLearnStore } from '@/stores/learn'
import { storeToRefs } from 'pinia'
const store = useLearnStore()
const idValueV1 = computed(() => store.getId) // 保证响应式
const { getId } = storeToRefs(store) // 响应式解构
const { increment } = store // actions方法可以直接解构
<script>
- state相关
const store = useStore() // 创建store实例
store.id++ // 访问state
store.$reset() // 将state重置为初始值
store.$patch(state => { // 变更state
state.id = 0
}
store.$subscribe(callbackFunction, { detached:true } // 订阅state, detached的值表示组件卸载后是否保留订阅
watch( pinia.state, callbackFunction, { deep:true }) // 侦听整个state
- getter相关
getters: {
getId: state => state.count * 2,
getId2():number { // 使用this引用其他getter,但是需要手动添加返回值类型
return this.getId * 2
}
}
- action相关
// action通过this访问整个store实例, 并支持完整的类型推断
const unsubscribe = store.$onAction(callbackFunction, true) // 订阅action, true布尔值标识组件卸载后是否保留
unsubscribe() // 手动删除订阅器
进阶操作
- 插件
1.1 支持范围:
- 为store添加新的属性
- 定义store时增加新的选项
- 为store增加新的方法
- 包装现有的方法
- 改变甚至取消action
- 实现副作用
- 仅应用于特定的store
1.2 使用方式
插件是通过pinia.use()添加到pinia实例
插件只会应用在pinia传递给应用后创建的store
1.3 定义方式
是一个函数,选择性地返回要添加到store的属性, 接受一个表示上下文的可选参数
1.3.1 扩展store
使用返回一个对象的方法,以便devtools追踪调试
/* 方式一 */
pinia.use(()=> ({hello: 'pinia'})
/* 方式二 */
pinia.use(({store}) => {
store.hello = 'pinia'
if(process.env.NODE_ENV === 'development') { // 确保新增的属性可以被devtools追踪到
store._customProperties.add('hello')
}
})
1.3.2 添加新的state
// 需要在store和store.$state上同时添加,并使用响应式API(ref()),以便在不同的读取中共享相同的值
pinia.use(({store}) => {
const hello = ref('pinia')
store.$state.hello = hello
store.hello = toRef(store.$state, 'hello')
// 备注: 此函数不需要返回,否则会在devtools中显示两次
// 插件中的变更发生在store被激活前,不会触发任何订阅函数
}
1.3.3 添加外部属性\第三方库的类实例\非响应式的简单值
// 需要使用markRaw()包装后再传递给pinia
import { markRaw } from 'vue'
pinia.use(({store}) => {
store.hello = markRaw('pinia')
})
1.3.4 在插件中调用$subscribe和¥onAction
- 在组件外使用store
需要确保pinia安装后在调用创建pinia实例的方法
在应用中可以使用$pinia获取pinia实例
易用操作
- 热更新 HRM
任何实现import.meta.hot规范的构建工具都可以正常工作
webpack使用的import.meta.webpackHot
import { defineStore, acceptHMRUpdate } from 'pinia'
const useAuth = defineStore('auth', { /* 配置 */ })
// 确保传递正确的store声明, 在每个store声明后都需要添加和调整这段代码
if(import.mrta.hot) {
import.meta.hot.accept(acceptHRMUpdate(useAuth, import.meta.hot))
}