• 学习pinia 介绍-State-Getters-Actions-Plugins


    可爱小菠萝🍍,安排一下!
    在这里插入图片描述
    内容基本参考官网:
    https://pinia.vuejs.org
    (官网的字体是Dank mono 不知道有没有跟我一样很喜欢的朋友😢 已经美美换上



    介绍

    pinia:最新一代的轻量级状态管理插件
    如果你之前使用过 vuex 进行状态管理的话,那么 pinia 就是一个类似的插件

    优点:

    • 完整的ts支持
    • 轻量
    • 去除了mutations,只有state、getters、actions

    安装

    npm i pinia
    
    • 1

    引入注册

    // main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    
    import {createPinia} from 'pinia'
    
    const app = createApp(App);
    
    const store = createPinia();
    app.use(store);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    初始化仓库Store

    1.根目录下新建store文件夹,再建一个index.ts
    2.main.ts
    store是用defineStore()定义的
    第一个参数传一个唯一的名称
    第二个参数还可以传一些别的比如getters、actions之类的,后面再说

    import { defineStore } from "pinia";
    
    export const useUserStore = defineStore('user', {
      state: () => ({
        // 初始化的值
        name: 'AIpoem',
        age: 20
      }),
      actions: {
        changeInfo() {
          this.name  = 'change poem'
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.在组件中使用
    实例化store之后,可以直接在store上访问任何定义在stategettersactions的属性
    store是经过reactive包装的对象,这意味着我们不需要写.value,但是就类似于props我们是不能解构store的

    <script setup lang="ts">
    import { useUserStore } from "./store";
    const userStore = useUserStore();
    
    // ❌❌❌ 这样会丢失响应性
    const { name, age } = userStore;
    script>
    
    <template>
      {{ userStore.name }},{{ userStore.age }}
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果需要从store中提出属性,同时保持其响应性,我们要用storeToRefs()
    它会为每一个属性都包上一层ref(会跳过action和任何不具有响应性的属性

    并且,action我们可以直接解构,它也是绑定在store身上的

    <script setup lang="ts">
    import { useUserStore } from "../store";
    import { storeToRefs } from "pinia";
    
    const userStore = useUserStore();
    const { name, age } = storeToRefs(userStore);
    const { changeInfo } = userStore;
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    State

    访问State

    可以通过store实例直接对state进行读和写

    const userStore = useUserStore();
    userStore.name = 'change poem';
    
    • 1
    • 2

    重置State

    可以调用store实例上的$reset()方法将state重置为初始值

    const userStore = useUserStore();
    console.log(userStore.name);  // AIpoem
    userStore.name = "change poem";
    
    userStore.$reset();			 
    console.log(userStore.name);  // AIpoem
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    改变State

    除了用store实例直接改变StateuserStore.name = "change poem"),也可以调用$patch()方法
    使用$patch()方法可以批量修改state

    1.$patch()传一个对象
    允许你对state进行部分更改

    const userStore = useUserStore();
    userStore.$patch({
      name: "change poem",
    })
    
    • 1
    • 2
    • 3
    • 4

    2.$patch()传一个函数
    但是当state中有数组的时候,上面那种传对象的方法就不太好用了,比如数组要新增、要删除一个元素,我们都要创建一个新数组来更新
    那这种时候传函数就更方便

    // 我上面的例子state中没有数组,这里就加一个数组演示一下
    // state: () => ({
    // 	// 初始化的值
    // 	name: "AIpoem",
    // 	age: 20,
    // 	hobby: ["吃", "喝", "玩", "乐"],
    // }),
    const userStore = useUserStore();
    // 这个state就是store实例上的state
    userStore.$patch(state => {
      state.hobby.push("睡")
    })
    // 传对象写法
    // userStore.$patch({
    //   hobby: ["吃", "喝", "玩", "乐", "睡"]
    // })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    替换State

    你可以给store实例的$state属性赋值一个新对象,这样能替换掉整个state

    const userStore = useUserStore();
    userStore.$state = {
      name: "change poem",
      age: 120,
      hobby: ["吃", "喝", "玩", "乐", "睡"],
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    订阅状态

    你可以通过store实例的$subscribe()方法来监视state的变化
    $subscribe()有两个参数:
    第一个参数是一个回调函数:

    const userStore = useUserStore();
    userStore.$subscribe((mutation, state) => {
      // 可能值:‘direct’ 'patch object' 'patch function'
      console.log(mutation.type) 		// 修改的方式
      console.log(mutation.storeId)		// defineStore()时传的名字
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第二个参数是固定值: { detached: true }
    组件卸载的时候,state的订阅也会自动卸载,如果我们希望订阅在组件卸载后还能保留,那就传第二个参数

    const userStore = useUserStore();
    userStore.$subscribe((mutation, state) => {
      ...
    }, { detached: true })
    
    • 1
    • 2
    • 3
    • 4

    Getters

    相当于store实例的computed,用来修饰值,并且是有缓存的

    如果只需要用到state,直接用就行

    export const useUserStore = defineStore('user', {
      state: () => ({
        name: 'AIpoem',
      }),
      getters: {
        sayName: state => `我的名字是${state.name}`
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用this

    如果需要用到其他getter,我们可以通过this来访问store实例
    使用了this的注意点:
    1.用了this就不能用箭头函数,否则this不指向store实例
    2.在ts中有必要定义返回值类型

    export const useUserStore = defineStore('user', {
      state: () => ({
        // 初始化的值
        name: 'AIpoem',
      }),
      getters: {
        sayName: state => `我的名字是${state.name}`,
        sayHi():string {
          return `你好, ${this.sayName}`
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    模板中使用,就跟用computed一样

    <script setup lang="ts">
    import { useUserStore } from "../store";
    const userStore = useUserStore();
    script>
    
    <template>
    	{{ userStore.sayName }} <br />
    	{{ userStore.sayHi }}
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    传参

    getters的传参方法也跟computed一样,就是return一个function,用这个function来接收参数

    export const useUserStore = defineStore('user', {
      state: () => ({
        name: 'AIpoem',
      }),
      getters: {
        isMyName: state => {
          return function(userName: string):boolean {
            return state.name === userName
          }
        }
        // 简写
        // isMyName: state => (userName: string) => state.name === userName
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    模板中直接传参就行:

    <script setup lang="ts">
    import { useUserStore } from "../store";
    const userStore = useUserStore();
    script>
    
    <template>
      {{ userStore.isMyName("AIpoem") }} <br />
      {{ userStore.isMyName("111") }}
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    ⚠️:如果getters返回了一个函数,它将不再缓存


    Actions

    相当于store实例的methods
    支持同步也支持异步

    同步

    import { defineStore } from "pinia";
    
    interface User {
      name: string,
      age: number
    }
    export const useUserStore = defineStore('user', {
      state: () => ({
        userInfo: <User>{},
      }),
      actions: {
        setUserInfo() {
          this.userInfo = {
            name: 'AIpoem',
            age: 20
          }
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    异步

    一般结合async await一起使用

    import { defineStore } from "pinia";
    
    interface User {
      name: string,
      age: number
    }
    
    const getInfo = (): Promise<User> => {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve({
            name: 'AIpoem',
            age: 20,
          })
        }, 3000)
      })
    }
    
    export const useUserStore = defineStore('user', {
      state: () => ({
        userInfo: <User>{},
      }),
      actions: {
        async setUserInfo() {
          this.userInfo = await getInfo()
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    订阅actions

    可以使用store实例的$onAction()方法来监视actions的调用
    $onAction()有两个参数:
    第一个参数是一个回调函数:

    userStore.$onAction(args => {
      // 调用的那个action的名字
      console.log(args.name); 
      // store实例	
      console.log(args.store); 
      // action成功调用并运行完触发
      args.after(() => {
        console.log("after");
      });
      // action抛错或返回一个失败的promise时触发
      args.onError(() => {
    	console.log("出错了");
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第二个参数是固定值: true
    组件卸载的时候,action的订阅也会自动卸载,如果我们希望订阅在组件卸载后还能保留,那就传第二个参数

    userStore.$onAction(args => {
      // 调用的那个action的名字
      console.log(args.name); 
      // store实例	
      console.log(args.store); 
      // action成功调用并运行完触发
      args.after(() => {
        console.log("after");
      });
      // action抛错或返回一个失败的promise时触发
      args.onError(() => {
    	console.log("出错了");
      });
    }, true);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Plugins

    我们可以通过写插件对piniastore进行一些扩展

    和vue一样,通过pinia.use()注册插件

    pinia的插件是一个函数
    pinia内部会帮我们调用这个插件函数,并且传回来一个可选的参数context

    ( 这部分演示的是js的写法,如果是ts还需要加一些东西,放在更后面了

    // main.js
    import { createApp, markRaw } from 'vue'
    import { router } from './router'
    import { createPinia } from 'pinia'
    
    const myPiniaPlugin = (context) => {
      // defineStore()时传进去的第二个参数
      console.log(context.options);
      // store实例
      console.log(context.store);
      
      // 可以给store实例添加一个全局属性
      context.store.globalProperty = '我是一个全局属性'
      
      // 可以给store实例添加一个新的state
      context.store.$state.newProperty = context.store.globalProperty;
      // $state可读可写
      console.log(context.store.$state);	// Proxy {newProperty: '我是一个全局属性'}
    
      // 添加第三方库的实例,需要用markRow()包裹,标记为不可响应式
      context.store.router = markRow(router)
    
      // 这两个订阅也可以调,在里面处理一些需要的逻辑
      context.store.$subscribe(() => {})
      context.store.$onAction(() => {})
    }
    
    const app = createApp(App)
    const store = createPinia()
    
    store.use(myPiniaPlugin)
    app.use(store)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    defineStore()时可以传第三个参数,他会出现在👆的context.options中,这样我们可以利用自定义的第三个参数来做一些事情

    使用ts编写插件:
    context的类型是PiniaPluginContext,这个要导进来写上

    1.如果为store实例添加了新的属性
    需要扩展PiniaCustomProperties接口

    // main.ts
    import 'pinia'
    import {createPinia, PiniaPluginContext} from 'pinia'
    
    declare module 'pinia' {
      export interface PiniaCustomProperties {
        globalProperty: string
      }
    }
    
    const myPiniaPlugin = (context: PiniaPluginContext) => {
      // 给store实例添加一个全局属性
      context.store.globalProperty = '我是一个全局属性'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.如果给store实例添加了新的state
    需要扩展PiniaCustomStateProperties接口

    ...
    declare module 'pinia' {
      export interface PiniaCustomStateProperties {
        newProperty: string
      }
    }
    
    const myPiniaPlugin = (context: PiniaPluginContext) => {
      // 给store实例添加一个全局属性
      context.store.$state.newProperty = context.store.globalProperty;
    }
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.如果添加了新的创建选项,也就是给defineStore()传了第三个参数
    需要扩展DefineStoreOptionsBase接口

    // 这我也不知道举什么例子了
    declare module 'pinia' {
      export interface DefineStoreOptionsBase {
        ...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (最后部分整的有点潦草我清楚我明白,原因是我还没有参透ts🙏)
    (等我学成归来xx等我需要用到的时候再研究一下🙏)
    (详情请咨询https://pinia.vuejs.org

  • 相关阅读:
    前端秘法基础式终章----欢迎来到JS的世界
    //路径累加和
    c++ 编译过程杂记等
    通付盾APP尽职调查报告:守护移动应用安全新篇章
    开发笔记 —— Linux 下的常用命令(一)
    Python之元组、字典和集合详解
    酷柚易汛ERP - 盘点操作指南
    2012年计网408
    java获取文件路径总结
    基于JAVA水星家纺网站计算机毕业设计源码+数据库+lw文档+系统+部署
  • 原文地址:https://blog.csdn.net/gegegegege12/article/details/125859402