likes
comments
collection
share

【聚焦前端实战】之光速入门Pinia使用和Pinia持久化,第一次用Pinia这篇文章就够了!

作者站长头像
站长
· 阅读数 19

前言:

因为自己的小项目之前没用类似于vuex这样状态管理的东西,现在又遇到了不得不用的时候,所以基于学新不学旧的原则我直接上Pinia大菠萝!实现用户信息的存储(以前是存在sessionStorage里)

开始入门Pinia

安装

yarn add pinia
// or
npm install pinia

Vue3版本

//main.js中
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia =createPinia()
const app =createApp(App)

app.use(pinia)
app.mount('#app')

使用Pinia

  1. state内定义的值
  2. getters内定义的计算属性函数(computer)
  3. action内定义的是方法函数(methods)
//@/store/mainStore.js

import {defineStore} from "pinia";

// 创建store,命名规则: useXxxxStore
// 参数1:store的唯一表示
// 参数2:对象,可以提供state actions getters

export constmainStore= defineStore('main',{
    state: () => {
        return {
            msg:"hello pinia!",
        }
    },
    getters: {

    },
    actions: {

    },
})

export defaultmainStore();

选项式API中使用

在官方文档中已经没有对Option API如何使用做对应说明了,我这边来告诉你如何使用。如代码所示:

<template>
  <div>
    {{test}}
  </div>

</template>
<script>
import {mainStore} from '@/store/mainStore.js'
const pinia = mainStore();
export default {
  name: "test",
  data(){
    return{
      test:pinia.msg
    }
  }

}

</script>

如果是需要使用其中的方法或者计算属性也是一样的道理,用 dot 使用就行。

如果是需要了解在组合式api中如何使用,可以看下面的所有代码,也可以在官网看。

【重点】如何对pinia中state定义的属性响应式?

原则上state中的属性默认就是响应式的,但是如果你用解构赋值的方法会破坏其响应式,所以我们要用它提供的一个方法storeToRefs

import {storeToRefs} from "pinia";
const store = useUserStore();
const { test } = storeToRefs(store);

这样就实现了响应式

但是笔者在使用的过程中遇到了一个问题,用了很多方法都没有能够解决,就是当我们用解构赋值一个对象或者对象内的属性时,即便使用了storeToRefs 也依旧无法变成响应式的,有大神知道这个问题如何解决的谢谢评论告知。

引入pinia持久化

安装引入

yarn add pinia-plugin-persistedstate
npm i  pinia-plugin-persistedstate

main.js中

import { createApp } from "vue";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
//这步肯定是之前就做好的
createApp(App).use(pinia);

使用

据说开起后是存在sessionStorage中但是我实验了一下发现其实是在localStorage中这可能稍微有些不太友好,后续会讲如何配置。

//在需要被使用的store中
import {defineStore} from "pinia";

export const useUserStore = defineStore("user", {
    state: () => {
        return {
            userData:{
            },
            test:"change?",

    }
    },
    getters:{
      getPhone(){
      }
    },
    actions:{
        initUser(Data){
            this.userData = Data;
        }
    },
    persist: true
})

配置文件

//在需要被使用的store中
import {defineStore} from "pinia";

export const useUserStore = defineStore("user", {
    state: () => {
        return {
            userData:{
            },
            test:"change?",

    }
    },
    getters:{
      getPhone(){
      }
    },
    actions:{
        initUser(Data){
            this.userData = Data;
        }
    },
    persist: {
        enabled:true, //开起持久化
        storage: sessionStorage, //储存模式
        paths: ['userData'], //指定储存的store
    },
})

笔者认为

但是我感觉这样做有点返璞归真,我们使用Pinia Vuex之类的东西的其中一种目的是不想把这些东西暴露在浏览器里(虽然用vue浏览器插件也能看到),但是持久化一旦存到了浏览器的这些储存里面的话,与直接存sessionStoragelocalStorage的优势仅仅是使用的代码方便点(这还是一种仁者见仁智者见智的看法),不知道后面会不会有大神去优化。

实战代码

个人是喜欢直接看代码,这样会理解的更加透彻,相信有部分读者也是如此以为,所以我就贴上这个的所有代码,可能有些冗余,但是大家看自己需要的部分和不理解的部分就行了。

store代码

import {defineStore} from "pinia";
export constuseUserStore= defineStore("user", {
    state: () => {
        return {
            userData:{
                id: -1,
                phone: null,
                singerName: null,
                username: null,
            },
            test:"change?",

    }
    },
    getters:{
      getPhone(){
          if (this.userData.phone){
              return this.userData.phone.replace(this.userData.phone.substring(3, 7), "****");
          }else {
              return undefined;
          }
      }
    },
    actions:{
        initUser(Data){
            this.userData = Data;
        }
    },
    persist: {
        enabled:true,
        storage:sessionStorage,
        paths: ['userData'],
    },
})

test.vue中使用

<template>
  <div>
    {{test}}
    <button @click="login">TEST BUTTON</button>
    <button @click="testFun">TEST BUTTON2</button>
    <div>
      用户信息:<br/>
      name:{{users.userData.username}}<br/>
      phone:{{users.userData.phone}}<br/>
<!--      id:{{userData.id}}<br/>-->
<!--      role:{{userData.role}}-->
    </div>
  </div>

</template>
<script setup>
import {useUserStore} from "@/store/userStore.js";
import {storeToRefs} from "pinia";
const users =useUserStore();
const { test } = storeToRefs(users);
const form = {};
const testFun = ()=>{
//-----------手动改变state值--------------
  users.$patch({test:"im changed!!!!"});
//---------使用getter方法------------------------
console.log(users.getPhone);
}

const login = ()=>{
singRequest.post("singer/login",form,{
    params:{
      phone:"xxxxxxxx",
      password:"xxx"
    }
  }).then(res =>{
    if (res.status === 200){
console.log(res.data);
      let userData = res.data;
//----------使用action方法------------------------------------
      users.initUser(userData);
//----------使用action方法------------------------------------
console.log("---------------登陆成功----------------------------")
    }else {
      this.$message({
        type:'error',
        message:'登陆失败,'+res.msg,
        center: true,
        duration:1000
      })
    }
  })
}

</script>

常见报错

  • getActivePinia was called with no active Pinia. Did you forget to install piniaconst pinia = createPinia()

【聚焦前端实战】之光速入门Pinia使用和Pinia持久化,第一次用Pinia这篇文章就够了!

这是因为没有在对应的js注册,虽然以及在main.js注册了,但是在有些特殊的地方会引用不到这时候就需要重新执行注册的代码(上文的app.use(pinia))但是显而易见的是每次都打那么多行代码必定是不方便的,所以我们把他集成,模块化一下。在store文件夹下新建index.js

import { createPinia } from 'pinia';
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
constpinia= createPinia();
pinia.use(piniaPluginPersistedstate);
export default pinia;

然后在main.js中引入pinia并且use

import pinia from "@/store/index.js";
app.use(pinia)

最后在对应报错的文件中

import {useUserStore} from "@/store/userStore.js";
importpiniafrom "@/store/index.js";
const userStore =useUserStore(pinia);