pinia状态管理(类似vuex,可以看作是vuex5.0版本,是最新一代的轻量级状态管理插件)
集中管理状态数据,简化组件通讯,单向数据流
1. pinia与vuex区别
- Vuex包括state,mutations,actions,getters。
- Pinia包括state,actions,getters(相当于data,methods,computed)
- Vuex调用数据用
$store.getters,调用方法用$store.dispatch() - Pinia可直接调用数据与方法,修改state还可用
$patch()进行批量修改。$reset重置状态、$subscribe订阅状态(监听状态变化)
2. Pinia特性:
- 没有mutations;
- actions支持同步异步;
- 没有模块的嵌套结构(没有模块化/没有namespaced命名空间),每个store
- 都是互相独立的,谁也不属于谁
- 更好的ts支持,vue2和vue3都支持
- 无需手动添加store,它的模块默认情况下创建就自动注册的
3. 基础使用
脚手架安装(npm init vue@latest)或手动安装
npm install pinia 安装pinia
npm i pinia-plugin-persist -S 安装pinia持久化存储插件
创建stores文件夹→index.js(创建pinia根存储,集成插件)
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'//引入pinia持久化存储插件
const storeRoot = createPinia()
storeRoot.use(piniaPluginPersist)//集成插件
export default storeRoot
main.js入口文件(集成pinia)
import { createApp } from "vue";
import router from "./router";
import store from "./store";
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import App from "./App.vue";
const app = createApp(App)
app.use(router);
app.use(store);
app.use(ElementPlus);
app.mount("#app");
示例一(直接调用数据与方法)
stores文件夹→user.js(定义store存储对象)
注意:getters中定义的方法名/计算属性名不能与state相同
import {defineStore} from 'pinia'
/**
* 定义名为useUserStore的存储对象
* defineStore方法
* 第一个参数: 模块名称是唯一的
* 第二个参数: 选项对象 state, actions, getters
* data methods computed
*/
export const useUserStore = defineStore('user',{
state(){
return {
account:null // 账户数据 {name,nick,password}
}
},
actions:{
// 具体业务逻辑,可以是同步或异步操作
saveAccount(account){
this.account = account
}
},
getters:{
//getters中定义的方法名/计算属性名不能与state相同
// userAccount:state => {
// return state.account
// }//定义方式1
userAccount(){
return this.account
}//定义方式2
}
})
Login.vue组件中使用
<template>
<div>
登录界面
<button @click="bindLogin">登录</button>
<!-- <p>{{ userStore.userAccount }}</p> --><!-- 相当于计算属性,依赖项变化自动更新 -->
<!-- <p>{{ userStore.account }}</p> --><!-- 相当于data -->
</div>
</template>
<script setup>
import {useRouter,useRoute} from 'vue-router'
import { useUserStore } from '@/store/user.js'
const router = useRouter() // 路由对象
const route = useRoute() // 路由信息对象
// this.$store.dispath('member/saveUser',{name:'jack',password:123})
const userStore = useUserStore()
console.log('userStore.account >>> :',userStore.account);
const bindLogin = ()=>{
router.push({path:'/home'})
console.log(route);
// 保存用户信息
userStore.saveAccount({nick:'jack',headerimg:'http://ip:port/xx.jpg'})
// store.dispatch('member/saveUser',{name:'jack',password:123}
}
</script>
<style lang="scss" scoped></style>
示例二(通过$patch批量修改state、$reset重置状态为初始值、$subscribe订阅状态(监听状态变化))
stores文件夹→counter.js(定义store存储对象)
import { defineStore} from 'pinia'
export const useCounterStore = defineStore('counter',{
state(){
return {
count:0,
message:''
}
},
actions:{
plus(){
this.count++
// console.log('plus ',this.count);
}
},
getters:{
// getters中定义的方法名(计算属性名称)不能与state相同
num(){
return this.count
},
doubleCount(){
return this.count * 2
}
}
})
Home.vue中使用
注意:解构数据会失去响应性
<template>
<div>首页</div>
<p>{{ counterStore.num }}</p>
<p>{{counterStore.doubleCount}}</p>
<p>{{counterStore.message}}</p>
<!-- 解构出来的状态失去响应式 -->
<!-- <p>{{count}}</p>
<p>{{num}}</p> -->
<h2>计数</h2>
<button @click="bindPlus">加一</button>
<button @click="bindMinus">减一</button>
<!-- 状态重置,$reset() -->
<button @click="counterStore.$reset()">重置</button>
</template>
<script setup>
import { useCounterStore } from '@/store/counter.js'
const counterStore = useCounterStore()
// const {count,plus,num} = counterStore//解构出来的状态失去响应式
//修改
const bindPlus = () => {
counterStore.plus()//在actions中修改
}
const bindMinus = () => {
counterStore.$patch({//$patch批量修改
count: counterStore.count - 1,
message:'hello'
})
}
// 监听状态数据变化,$subscribe
counterStore.$subscribe(()=>{
console.log('subscribe >>>> ');
})
</script>
<style lang="scss" scoped></style>