Vue学习记录之二十七 Pinia的使用

Pinia 是一个用于 Vue.js 的状态管理库,旨在取代 Vuex,提供更现代的 API 和更好的开发体验。

一、安装

pnpm install pinia -s  //运行时依赖

二、配置

在 main.ts中

import {
    
     createApp } from 'vue'
import App from './App.vue'
import {
    
     createPinia } from 'pinia'  //导入依赖
const store = createPinia()
let app = createApp(App)
app.use(store)                      //注册组件
app.mount('#app')

三、创建一个 Store

src/store/index.ts

import {
    
     defineStore } from 'pinia'
import {
    
    Names} from './store-name'
export const useTestStore = defineStore(Names.TEST,{
    
    
    state:()=>{
    
    
        return {
    
    
            current: 20,
            name: "lvmanba"
        }
    },
    //computed 修饰一些值
    getters:{
    
    
        doubleCount: (state) => state.current * 2,
    },
    //methods 可以做同步,异步都可以做。提交state
    actions:{
    
    
        setCurrent(num:number){
    
    
            this.current = num
        }
    }

})

// 热重载支持
if (import.meta.hot) {
    
    
  import.meta.hot.accept((newModule) => {
    
    
    useCounterStore.hotUpdate(newModule.useCounterStore);
  });
}

src/store/store-name.ts

export const enum Names{
    
     //定义了一个名为Names的枚举
    TEST = 'TEST'
}

四、使用

<template>
    <div>demo</div>
    <div>
      pinia:{
   
   {Test.current}} - {
   
   {Test.name}}
    </div>
    <div>{
   
   { Test.doubleCount }}</div>
    <div>
      <button @click="change">修改pinia中的current</button>
    </div>
</template>
<script setup lang='ts'>
import {
      
       ref,reactive } from 'vue'
import {
      
       useTestStore } from './store/index'
const Test = useTestStore()
// 方法1
/*
const change = () => {
  Test.current++
}
*/
// 方法2 通过patch
/*
const change = () => {
  Test.$patch({
    current: 888,
    name: "绿曼巴"
  })
}
*/
// 方法3, 还是使用patch, 他接收一个工厂函数,里面可以处理逻辑
/*
const change = () =>{
  Test.$patch((state)=>{ //state 就是我们pinia中的state.
    state.current++
    state.name = '方世玉'
  })
}
*/
// 方法4,不常用,有弊端,修改的话,需要修改整个对象,必须修改所有的值
/*
const change = () => {
  Test.$state = {
    current:2000,
    name:"少年没有乌托邦,心向远方自明朗"
  }
}
*/
// 方法5  使用defineStore定义的store中的action中的方法

const change = () => {
      
      
  Test.setCurrent(567)
}


</script>
<style scoped>

</style>

五、实例

代码的结构和上面一样: 功能是实现同步和异步调用。
App.vue

<template>
    <div>demo
      <p> aciions-user: {
   
   { Test.user}}</p>
      <hr />
      <p> aciions-name: {
   
   { Test.name}}</p>
      <hr />
      <p> getters: {
   
   { Test.newName}}</p>
      <hr>
      <button @click="change">修改pinia中的current</button>
    </div>
</template>
<script setup lang='ts'>
import {
      
       ref,reactive } from 'vue'
import {
      
       useTestStore } from './store/index'
const Test = useTestStore()

const change = () => {
      
      
  Test.setUser()
}
</script>
<style scoped>

</style>

src/store/index.ts

import {
    
     defineStore } from 'pinia'
import {
    
    Names} from './store-name'

type User = {
    
    
    name: string,
    age:number
}
/*
// 同步
let result:User = {
    name:"飞机",
    age: 18
}
*/

const Login = ():Promise<User> => {
    
    
    return new Promise((resolve)=>{
    
    
        setTimeout(()=>{
    
    
            resolve({
    
    
                name: 'lmb',
                age: 42
            })
        },2000)
    })
}

export const useTestStore = defineStore(Names.TEST,{
    
    
    state:()=>{
    
    
        return {
    
    
            user:<User>{
    
    },
            name: "小飞机"
        }
    },
    //computed 修饰一些值
    getters:{
    
    
        newName():string{
    
      //需要设置返回值类型,要不报错。
            return `$-${
      
      this.name}-${
      
      this.getUserAge}`
        },
        getUserAge():number{
    
    
            return this.user.age
        }
    },
    //methods 可以做同步,异步都可以做。提交state
    actions:{
    
    
        async setUser(){
    
    
            const result = await Login();
            this.user = result;
            this.setName('大飞机')
        },
        setName(name:string){
    
    
            this.name = name
        }
    }

})

六、Pinia的API

1、$reset()

调用reset可以让值恢复到state定义的原始值
如在App.vue

<template>
    <div>
      <button @click="reset">reset</button>
    </div>
</template>
<script setup lang='ts'>
import {
      
       ref,reactive } from 'vue'
import {
      
       useTestStore } from './store/index'
const Test = useTestStore()

const reset = () => {
      
      
  Test.$reset()
}
</script>

2、$subscribe

$subscribe 方法用于监听 store 中状态的变化,只要发生变化,就自动调用。它接受一个回调函数,该函数会在每次 store 状态发生变化时被调用。回调函数有两个参数:

  • mutation:一个对象,包含关于状态变化的信息。典型的字段包括 storeId(store 的 ID)、type(变化的类型,例如 patch 或 direct)、events(变化的详细信息)。
  • state:变化后的新状态。
const unsubscribe = Test.$subscribe((mutation, state) => {
    
    
  console.log(mutation);  // mutation 是一个描述状态变化的对象
  console.log(state);     // state 是变化后的新状态
});

// 如果你想取消订阅,可以调用 unsubscribe 函数
unsubscribe();

3、$onAction

$onAction 是一个方法,用于监听 store 中 action 的调用。通过这个方法,你可以在 action 被调用之前和之后执行一些代码,比如记录日志、性能监控或错误处理等。

const off = store.$onAction(({
    
     name, store, args, after, onError }) => {
    
    
  console.log(`Action ${
      
      name} was called with args:`, args);

  // 在 action 执行后执行一些代码。一个函数,接受一个回调函数,该回调函数会在 action 执行完毕后被调用,并传入 action 的返回值。
  after((result) => {
    
    
    console.log(`Action ${
      
      name} finished with result:`, result);
  });

  // 在 action 执行时发生错误时执行一些代码
  onError((error) => {
    
    
    console.error(`Action ${
      
      name} failed with error:`, error);
  });
});

// 如果你想取消监听,可以调用 off 函数
off();

七、常见的问题

1、Pinia 支持热重载,但是需要单独设置,你可以在开发过程中修改 store 而无需刷新整个页面:

if (import.meta.hot) {
    
    
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore, import.meta.hot));
}

2、解构出来的变量不具备响应性,需要用到storeToRefs

import {
    
     storeToRefs } from 'pinia'
// const {current,name} = Test
// 这样current,name就具备了响应式
const {
    
    current,name} = storeToRefs(Test)

八、持久化

pinia和vuex 都有一个通病页面刷新状态会丢失。我们可以写一个pinia插件缓存他的值。
可以使用 pinia-plugin-persist 插件。这个插件允许你将状态存储到 LocalStorage 或 SessionStorage 中,从而在页面刷新后保留状态。

npm install pinia pinia-plugin-persist

配置

import {
    
     createApp } from 'vue';
import {
    
     createPinia } from 'pinia';
import piniaPersist from 'pinia-plugin-persist';  //导入依赖
import App from './App.vue';

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

pinia.use(piniaPersist);  //注册插件

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

使用:

import {
    
     defineStore } from 'pinia';

export const useMainStore = defineStore({
    
    
  id: 'main',
  state: () => ({
    
    
    counter: 0,
    user: {
    
    
      name: 'John Doe',
      age: 30
    }
  }),
  actions: {
    
    
    increment() {
    
    
      this.counter++;
    },
    setUser(name, age) {
    
    
      this.user.name = name;
      this.user.age = age;
    }
  },
  persist: {
    
    
    enabled: true,
    strategies: [
      {
    
    
        key: 'main_store',
        storage: localStorage, // 你也可以使用 sessionStorage
      },
    ],
  },
});

读取存储

<template>
  <div>
    <p>Counter: {
    
    {
    
     counter }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script setup lang="ts">
import {
    
     useMainStore } from './stores/main';

// 获取 store 实例
const mainStore = useMainStore();

// 解构需要的状态和方法
const {
    
     counter, increment } = mainStore;
</script>

猜你喜欢

转载自blog.csdn.net/LvManBa/article/details/143362395