pinia
pinia成为正式的vue状态库,pinia就是vuex5
- 同时支持 Composition Api 和 Options api 的语法
- 去掉 mutations ,只有 state 、getters 和 actions
- 不支持嵌套的模块,通过组合 store 来代替
- 更完善的 Typescript 支持
- 清晰、显式的代码拆分
用法
- 安装
npm install pinia
或者yarn add pinia
- main.js中引入
import App from './App.vue'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
- 配置store.js
import { defineStore } from 'pinia'
// defineStore 调用后返回一个函数,调用该函数获得 Store 实体
export const useStore = defineStore({
// id: 必须,在所有 Store 中唯一
id: 'globalState',
// state: 返回对象的函数
state: () => ({
count: 1,
data: {
name: 'Jerry',
sex: '男'
}
}),
// getter 第一个参数是 state,是当前的状态,也可以使用 this 获取状态
// getter 中也可以访问其他的 getter,或者是其他的 Store
getters: {
// 通过 state 获取状态
doubleCount: (state) => state.count * 2,
// 通过 this 获取状态(注意this指向)
tripleCount() {
return this.count * 3
}
},
actions: {
updateData (newData, count) {
// 使用 this 直接修改
this.data = { ...newData }
this.count = count
// 使用 $patch 修改多个值
this.$patch({
data: { ...newData },
count
})
}
}
})
- 使用store
<template>
// 获取 store 的 state
<p>姓名:{{store.data.name}}</p>
<p>性别:{{store.data.sex}}</p>
// 调用 mutations 方法 / 修改 store
<button @click='update'>修改用户信息</button>
// 获取 getter
<p>获取getter:{{store.doubleCount}}</p>
</template>
<script setup>
import { useStore } from '@store/store.js'
const store = useStore()
function update () {
// 通过 mutations 定义的方法修改 state
store.updateData({ name: 'Tom', sex: '女' })
// 通过 store 直接修改
store.data = { name: 'Tom', sex: '女' }
// 同时改变多个状态
store.$patch((state) => {
state.data = { name: 'Tom', sex: '女' }
state.count = 2
})
}
</script>
<style lang="scss" scoped>
</style>
- 替换整个state
$state 可以让你通过将 store 的属性设置为新对象来替换 store 的整个 state
const store = useStore()
store.$state = {
name: 'Bob',
sex: '男'
}
- 重置状态
可以通过store上的$reset()方法重置为初始值状态
const store = useStore()
store.$reset()
pinia在setup之外使用
在工作中需要在路由守卫中去请求用户信息将用户信息放到pinia中。
import { createRouter } from 'vue-router'
const router = createRouter({
// ...
})
// ❌ 根据导入的顺序,这将失败
const store = useStore()
router.beforeEach((to, from, next) => {
// 我们想在这里使用 store
if (store.isLoggedIn) next()
else next('/login')
})
解决办法:确保始终应用此功能的最简单方法是延迟调用 useStore(),方法是将它们放在安装 pinia 后始终运行的函数中。
router.beforeEach((to) => {
// ✅ 这将起作用,因为路由器在之后开始导航
// 路由已安装,pinia 也将安装
const store = useStore()
if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})