• [Vue3] pinia状态管理


    1.pinia的介绍

    Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 export const state = reactive({}) 来共享一个全局状态。

    与 Vuex 相比,Pinia 不仅提供了一个更简单的 API,也提供了符合组合式 API 风格的 API,最重要的是,搭配 TypeScript 一起使用时有非常可靠的类型推断支持。

    Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。

    1. mutation 已被弃用。它们经常被认为是极其冗余的。它们初衷是带来 devtools 的集成方案,但这已不再是一个问题了。
    2. 无需要创建自定义的复杂包装器来支持 TypeScript,一切都可标注类型,API 的设计方式是尽可能地利用 TS 类型推理。
    3. 无过多的魔法字符串注入,只需要导入函数并调用它们,然后享受自动补全的乐趣就好。
    4. 无需要动态添加 Store,它们默认都是动态的,甚至你可能都不会注意到这点。注意,你仍然可以在任何时候手动使用一个 Store 来注册它,但因为它是自动的,所以你不需要担心它。
    5. 不再有嵌套结构的模块。你仍然可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间,虽然是 Pinia 从设计上提供的是一个扁平的结构,但仍然能够在 Store 之间进行交叉组合。你甚至可以让 Stores 有循环依赖关系。
    6. 不再有可命名的模块。考虑到 Store 的扁平架构,Store 的命名取决于它们的定义方式,你甚至可以说所有 Store 都应该命名。

    2.pinia的配置

    yarn add pinia
    # 或者使用 npm
    npm install pinia
    
    • 1
    • 2
    • 3

    main.js

    import { createApp } from 'vue'
    import { createPinia } from 'pinia'  // 引入pinia
    import App from './App.vue'
     
    const pinia = createPinia()    // 创建实例
    const app = createApp(App)
     
    app.use(pinia)    // 安装插件
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    在这里插入图片描述

    3.state状态管理

    Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的 data、 computed 和 methods。

    3.1 state的基本使用

    在这里插入图片描述

    src/store/counter.js

    1.Option Store:与 Vue 的选项式 API 类似,我们也可以传入一个带有 state、actions 与 getters 属性的 Option 对象

    在这里插入图片描述

    import { defineStore } from 'pinia'
     
    // 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,
    // 同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
    // 第一个参数是你的应用中 Store 的唯一 ID。
    export const useStore = defineStore('main', {
      state: () => ({ count: 0 }),
      getters: {
        double: (state) => state.count * 2,
      },
      actions: {
        increment() {
          this.count++
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.Setup Store:也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

    在这里插入图片描述

    import { defineStore } from 'pinia'
    import { computed, ref } from 'vue'
     
    export const useCounterStore = defineStore('counter', () => {
      // state
      const count = ref(0)
     
      // getters
      const double = computed(() => count.value * 2)
      
      // actions
      function increment () {
        count.value++
      }
     
      return { count, double, increment }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    src/App.vue

    <template>
      <div>
        <h1>我是app</h1>
        {{ counter.count }}
        {{ count }}
      </div>
    </template>
     
    <script setup>
    import { useCounterStore } from '@/stores'
    import { storeToRefs } from 'pinia'
    const counter = useCounterStore()
     
    // ❌ 这将无法生效,因为它破坏了响应性
    // 这与从 `props` 中解构是一样的。
    const { count, double } = counter
     
     
    // `name` and `doubleCount` 都是响应式 refs
    // 这也将为由插件添加的属性创建 refs
    // 同时会跳过任何 action 或非响应式(非 ref/响应式)属性
    const { count, double } = storeToRefs(counter)
    // 名为 increment 的 action 可以直接提取
    const { increment } = counter
     
    </script>
    
    • 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
    3.2 state的访问

    得到state的值。

    import { useCounterStore } from './store/counter' // 导入创建好的counter.js
    const counter = useCounterStore()    // 实例化
     
    console.log(counter.count)    // 0import { useCounterStore } from './store/counter' // 导入创建好的counter.js
    const counter = useCounterStore()    // 实例化
     
    console.log(counter.count)    // 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    store 的 $reset() 方法将 state 重置为初始值。

    import { useCounterStore } from './store/counter' // 导入创建好的counter.js
    const counter = useCounterStore()    // 实例化
     
    counter.$reset()    // store 的 $reset() 方法将 state 重置为初始值。
    
    • 1
    • 2
    • 3
    • 4

    修改state的4种方法。

    <script setup>
    import { useCounterStore } from './store/counter'
    const counter = useCounterStore()
     
    // 方式1 
    counter.count++
     
    //以下两种方式可以一次性修改多个值
     
    // 方式2: $patch 对象写法
    counter.$patch({
      count: counter.count + 1,
    })
     
    // 方式3: $patch 函数写法
    counter.$patch((state) => {
      // state 是 counter里的state
      state.count = state.count + 1
    })
     
    // 方式4: 通过 actions 创建的函数修改
    counter.increment()
     
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    $subscribe对state的订阅。

    <script setup>
    import { useCounterStore } from './store/counter'
    const counter = useCounterStore()
     
    // 必须先订阅在修改才会触发
    counter.$subscribe((mutation, state) => {
      console.log(mutation)
      console.log(state)
      /**
       * 其中 state 是 mainStore 实例,
       * 而 mutation mutation对象主要包含三个属性
            events : 是这次state改变的具体数据,包括改变前的值和改变后的值等等数据
            storeId :是当前store的id
            type:type表示这次变化是通过什么产生的,主要有三个分别是
              “direct” :通过 action 变化的
              ”patch object“ :通过 $patch 传递对象的方式改变的
              “patch function” :通过 $patch 传递函数的方式改变的
       */
     
      // 每当状态发生变化时,将整个 state 持久化到本地存储。
      localStorage.setItem('counter', JSON.stringify(state))
    })
     
    // 修改state值
    counter.increment()
     
    </script>
    
    • 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

    4.getters

    export const useCounterStore = defineStore('Counter',{
      state: () => {
        return {
          name: '快乐超人',
        }
      },
      getters: {
        formatName: (state) => {
          return state.name + '00';
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    import { useCounterStore } from './store/counter'
    const counter = useCounterStore()
     
    counter.formatName    //快乐超人00import { useCounterStore } from './store/counter'
    const counter = useCounterStore()
     
    counter.formatName    //快乐超人00
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    getters传入参数。

    export const useCounterStore = defineStore('Counter', {
      getters: {
        getUserById: (state) => {
          return (userId) => state.users.find((user) => user.id === userId)
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    import { useCounterStore } from './store/counter'
    const counter = useCounterStore()
     
    counter.getUserById(2)
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    Docker 基本管理
    微信小程序中生成普通二维码,并根据二维码里的参数跳转对应的页面
    湖南大学大二STC单片机实训学习记录
    SpringCloud
    【无标题】
    Dubbo 之 线程池
    KeeWiDB的高性能修炼之路:架构篇
    音视频 SDL vs2017配置
    使用vscode开发esp32
    长沙市2022年成人高考疫情防控补充公告
  • 原文地址:https://blog.csdn.net/qq_43141726/article/details/134477010