「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」
pinia是 Vue.js 的轻量级状态管理库,pinia简化了vuex的相关操作过程和相关概念。可以认为是下一代的vuex,也就是vuex5.0
- 在pinia中 即支持options api 也支持composition api
- 在pinia中没有modules和mutations概念,actions中既可以做同步操作也可以做异步操作
- 可以更好的和TypeScript进行兼容
- 支持vue devTools
- pinia只能被用于vue框架中
从上图中可以看出,使用pinia创建的每一个store其实就是一个个的模块,这些store会被统一挂载到一个root store中,作为它的子模块来进行使用
基本使用
安装
npm install pinia
基本使用
main.ts --- 全局注册pinia
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
// 创建pinia实例
const pinia = createPinia()
const app = createApp(App)
// 注册pinia
app.use(pinia)
app.mount('#app')
store/index.ts
import { defineStore } from 'pinia'
// 定义一个store
// defineStore函数 会返回一个帮助我们使用store的hook函数
// 参数1 --- store的名称 --- 必须唯一
// 参数2 --- 配置对象
export const useUserInfoStore = defineStore('userInfo', {
// store中的data
state() {
return {
count: 100
}
},
// store中的computed
getters: { },
// store中的methods
actions: { }
})
App.vue --- 使用
<template>
<div>
count: {{ userInfoStore.count }}
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from './store'
// 调用hook,生成对应的store --- 类型是一个proxy
const userInfoStore = useUserInfoStore()
</script>
解构
<template>
<div>
count: {{ count }}
<button @click="() => count++">increment</button>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useUserInfoStore } from './store'
const userInfoStore = useUserInfoStore()
// 默认情况下 pinia对store中的state进行的响应式代理
// 而解构出来的值并不是响应式的
// const { count } = userInfoStore
// 为此 pinia提供了 和vue3中toRefs相同功能的方法 storeToRefs
// 解构出来的值 都是一个个的ref对象
const { count } = storeToRefs(userInfoStore)
</script>
状态修改
方式一:
<template>
<div>
name: {{ store.name }}
count: {{ store.count }}
<button @click="change">change</button>
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from './store'
const store = useUserInfoStore()
// 修改方式一: 分开依次更新
const change = () => {
store.name = 'Alex'
store.count++
}
</script>
方式二:
<template>
<div>
name: {{ store.name }}
count: {{ store.count }}
<button @click="change">change</button>
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from './store'
const store = useUserInfoStore()
// 修改方式二: 多个store需要更新的时候,推荐使用批量更新
const change = () => {
// 参数可以是对象
// store.$patch({
// name: 'Alex',
// count: ++store.count
// })
// 参数可以是函数 --- 常见
store.$patch(state => {
state.name = 'Alex'
state.count++
})
}
</script>
方式三:
store/index。ts
import { defineStore } from 'pinia'
export const useUserInfoStore = defineStore('userInfo', {
state() {
return {
name: 'Klaus',
count: 0
}
},
// 在actions中的this就是当前store对象
actions: {
// 在这里可以进行参数的传递
// 注意: 如果此时内部使用了this,那么actions中的函数不可以写成箭头函数
change(num: number) {
// 在这里可以分开更新对应的store
// 也可以使用$patch对多个store进统一更新
this.$patch(state => {
state.name = 'Alex'
state.count += num
})
}
}
})
App.vue
<template>
<div>
name: {{ store.name }}
count: {{ store.count }}
<button @click="change">change</button>
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from './store'
const store = useUserInfoStore()
// 方式三: 将业务逻辑封装到action中
const change = () => store.change()
</script>
getters
import { defineStore } from 'pinia'
export const useUserInfoStore = defineStore('userInfo', {
// state必须写成箭头函数,以便于ts可以正确的进行类型推导
// 如果写成普通的function,ts可能无法准确的进行类型推导
state: () => {
return {
name: 'Klaus',
count: 0
}
},
// 和vuex一样这里放置计算属性 --- 有缓存功能
getters: {
// state会在这里被传入
doubleCount(state) {
return state.count * 2
}
},
actions: {
change() {
this.$patch(state => {
state.name = 'Alex'
state.count++
})
}
}
})
import { defineStore } from 'pinia'
export const useUserInfoStore = defineStore('userInfo', {
state: () => {
return {
name: 'Klaus',
count: 0
}
},
getters: {
// 在getters中我们依旧可以正确获取对应的this
// 但是此时ts并没有办法正确推导出函数的返回值,所以我们需要手动进行标注
doubleCount(): number {
// 在getters中依旧可以使用this获取当前store对象的原因是
// 方便我们在一个getter函数中,调用另一个getter函数的返回值
return this.count * 2
}
},
actions: {
change() {
this.$patch(state => {
state.name = 'Alex'
state.count++
})
}
}
})
import { defineStore } from 'pinia'
export const useUserInfoStore = defineStore('userInfo', {
state: () => {
return {
name: 'Klaus',
count: 0
}
},
getters: {
// 也可以在函数形参中加上state参数
// 目的是为了ts可以正确的推导出函数的返回值
// 而不需要手动添加对应的类型注解
doubleCount(state) {
return this.count * 2
}
},
actions: {
change() {
this.$patch(state => {
state.name = 'Alex'
state.count++
})
}
}
})