状态管理pinia

2 阅读1分钟

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.count2
        }
    }
})

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.count1,
        message:'hello'
    })
}

// 监听状态数据变化,$subscribe
counterStore.$subscribe(()=>{
    console.log('subscribe >>>> ');
})
</script>
<style lang="scss" scoped></style>