6.1 KiB
Executable File
6.1 KiB
Executable File
pinia 2.x
优势:
- 适配vue3的composition api特性
- 可脱离组件使用
- 支持热更新
- 体积小(1KB)
- 支持 TypeScript
- 支持ssr
- 进入vue官方库, 接近 Vuex 5.x 的提案
不足:
- devtool 部分功能不支持
和 vuex3.x/4.x 的比较:
- 没有mutation
- action既可以执行异步方法, 也可以执行同步方法
- 没有命名空间(或者说每个store都是一个空间, 扁平状态)
- store是动态的
本文档只整理vue3 composition api 部份
安装
yarn add pinia
简单使用
store 有三个概念, state, getters, actions, 类似vue2中的data, computed, methods
// 创建
// @/store/index.ts
import type { App } from 'vue'
import {createPinia} from 'pinia'
const store = createPinia()
export function setupStore(app: App<Element>){
app.use(store)
}
export {store}
// 使用
// @/main.ts
import { createApp } from 'vue'
import {setupStore} from './store'
import App from './App.vue'
const app = createApp(App)
setupStore(app)
app.mount('#app')
// 定义容器
// @/store/modules/app.ts
import { defineStore } from "pinia"
import {store } from '../index'
// 返回值是个函数
export const useAppStore = defineStore({
// 唯一ID,可以配合 Vue devtools 使用
id: 'app',
// 必须是函数: 避免服务端渲染时交叉请求污染数据;
// 箭头函数: 为了更好的类型推导
state: (): any => ({
count: 0, // 这些属性都会自动推断类型
}),
// getters有缓存
// getters函数默认接收一个可选参数state, 带上state时能自动推断函数返回, 不带state, 就得声明返回类型
getters: {
countIsEven(): boolean {
return this.count % 2 === 0 // 像vue2使用data一样
}
},
actions: {
// action不能用箭头函数, this问题
countAddOne(): void {
this.count ++
}
}
})
// export const useStore = defineStore('app', {}), 也可以这样传, 第一个参数是id, 是唯一的
// 在setup之外的地方引用
export function useAppStoreWithOut(){
return useAppStore(store)
}
<!--在组件中使用-->
<template>
{{appStore.count}}
{{appStore.countIsEven}}
<button @click="countAddOne">增加</button>
</template>
<script setup lang="ts">
import {useAppStore} from '@/store/modules/app'
const appStore = useAppStore() // 导入的是函数, 执行后得到 reactive, 具有响应性
const countAddOne = ()=>{
// 更改state有三种方式
// 1. 直接修改
appStore.count++ // reactive不用.value
// 2. $patch(), 针对多个更新有性能优化
// 2.1 传对象
appStore.$patch({count: appStore.count + 1})
// 2.2 传函数
appStore.$patch(state => {
state.count++
})
// 3. 调用action, 复杂逻辑推荐使用action
appStore.countAddOne()
}
</script>
// 在组件外使用: 在组件内使用时, pinia已经注册到app实例了, 但在组件外时, 不一定. 所以需要手动传 store
import {useAppStoreWithOut} from '@/store/modules/app'
const appStore = useAppStoreWithOut()
其他写法: 像setup函数一样定义store
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
storeToRefs()
// store是一个reactive, 不能解构, 否则会失去响应性. 想保存响应性, 需要使用 storeToRefs()方法
import {useAppStore} from '@/store/modules/app'
import { storeToRefs } from 'pinia'
const appStore = useAppStore()
const {count} = storeToRefs(appStore) // 会自动跳过action和不是响应性的属性
// 当然在computed里返回 appStore.count 也能实现响应性 const isEven2 = computed(()=>{ return appStore.isEven })
// toRef('count', appStore.count) 也能实现响应性
$reset()
// 用$reset()方法来把state恢复为初始值
const appStore = useAppStore()
store.$reset()
$patch()
store.$patch({
list: [1, 2, 3, 4, 5],
name: 'Abalam',
}) // 这样写有时太消耗性能, 比如修改数组时还得新建一个数组
// $patch()可以接收一个函数作为参数, 该函数的默认参数是state
store.$patch(state => {
state.list.push(6)
state.name = 'Jan'
})
$state
// 通过store的$state属性,整个替换state对象
store.$state = { counter: 666, name: 'Paimon' }
$subscribe()
// 用$subscribe()来订阅state的改变
appStore.$subscribe((mutation, state) => {
console.log('mutation', mutation)
/* mutation: {
type: 'direct' | 'patch object' | 'patch function',
storeId: 'app',
} */
console.log('state', state) // 应用举例: state变化时存到localStorage
})
// 默认情况下,state侦听会和组件绑定在一起(如果store是在组件的setup中)。这意味着,当组件卸载时,侦听会自动被移除。如果你需要在组件被卸载时,侦听仍然保持,需要给$subscribe()方法传递第二个参数true
appStore.$subscribe(callback, true)
// 当然, 也可以用watch监听整个state
watch(
pinia.state,
(state) => {
// ...
},
{ deep: true }
)
$onAction()
// 用store.$onAction()方法侦听、订阅action的调用与结果。在action调用前就会调用这个回调。可以在after回调中改变action的返回结果。在onError回调中可以处理错误。
// 应用场景: 在运行时跟踪错误
const ubsubscribe = someStore.$onAction(
({
name,
store,
args,
after,
onError
}) => {
const startTime = Date.now()
// after会在完成调用后执行
after(result => {
console.log(`花费时间: ${Date.now() - startTime} ms`)
})
onError(error => {
console.warn(error)
})
}
)
// 可手动移除监听
ubsubscribe()
// 默认情况下,actions的侦听是在组件初始化是加上的(如果store是在一个组件的setup中使用)。这意味着组件卸载时,侦听会自动被移除。如果你想要组件卸载时,不移除侦听,在组件中调用$onAction时加上第二个参数true
someStore.$onAction(callback, true)