1、状态操作 actions

actions 可以通过完全输入(和自动完成 ✨)支持访问整个容器实例。actions 是异步的,可以在其中等待任何 API 调用甚至其他 actions 。

① 状态更新

  1. 首先在src/store/index.ts文件中的pinia实例中,创建一个actions方法:

    import { defineStore } from 'pinia' // 导入 pinia 中的功能模块
    
    // 创建容器
    // 参数一:容器名
    // 参数二:容器的内容
    const useMainStore =  defineStore('main', {
      // pinia 状态管理的数据,通过箭头函数返回一个对象
      // 相当于 vue 中的 data 数据
      state: () => {
        return {
          message1: 'Hello',
          message2: 'Pinia',
          count: 1
        }
      },
    
      // 相当于 vue 中的 computed 计算属性
      getters: {},
    
      // 相当于 vue 中的 methods 方法
      actions: {
        **// 1、count 加法方法
        addCount() {
          this.count++
        }**
      }
    })
    
    // 导出容器
    export {
      useMainStore
    }
    
  2. src/components/MyPinia.vue页面组件中进行pinia的actions方法的调用,此处有三种调用的方式:

    • 方法一: 在标签中绑定actions事件

      <template>
        <h4>没有通过解构获得的 count:{{ mainStore.count }}</h4>
        <h4>通过解构获得的 count:{{ count }}</h4>
      
        <button @click="getStore">按钮</button>
        **<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>**
      </template>
      
      <script setup lang="ts">
      // 导入 pinia 中的 storeToRefs 方法
      import { storeToRefs } from 'pinia';
      // 导入 pinia 实例
      import { useMainStore } from '../store/index'
      
      // 实例化容器
      const mainStore = useMainStore()
      
      // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
      // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
      const { message1, message2, count } = storeToRefs(mainStore)
      
      // 按钮点击事件
      const getStore = () => {
        mainStore.count++
      }
      </script>
      
      <style scoped></style>
      

      在这里插入图片描述

    • 方法二: 自定义一个方法,在这个方法中去调用对应的actions方法:

      <template>
        <h2>{{ message1 }}</h2>
        <h3>{{ message2 }}</h3>
        <h4>没有通过解构获得的 count:{{ mainStore.count }}</h4>
        <h4>通过解构获得的 count:{{ count }}</h4>
      
        <button @click="getStore">按钮</button>
        <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
        **<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>**
      </template>
      
      <script setup lang="ts">
      // 导入 pinia 中的 storeToRefs 方法
      import { storeToRefs } from 'pinia';
      // 导入 pinia 实例
      import { useMainStore } from '../store/index'
      
      // 实例化容器
      const mainStore = useMainStore()
      
      // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
      // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
      const { message1, message2, count } = storeToRefs(mainStore)
      
      // 按钮点击事件
      const getStore = () => {
        console.log(message1 + " " + message2 + " " + count);
        mainStore.count++
      }
      
      **// 自定义的 count 加法方法
      const addCount = () => {
        mainStore.addCount()
      }**
      </script>
      
      <style scoped></style>
      

      在这里插入图片描述

    • 方法三: pinia中提供了一个方法$patch,向上面两种方法调用actions去改变state的时候,会有留下state值的历史记录(时间旅行)。但是如果不通过actions,而是直接去修改state的值的话,例如直接通过mainStore.count++这种方式修改state的值,就不会留下state的历史记录。而$patch方法可以直接去修改state中的值,并且留下历史记录:

      <template>
        <h2>{{ message1 }}</h2>
        <h3>{{ message2 }}</h3>
        <h4>没有通过解构获得的 count:{{ mainStore.count }}</h4>
        <h4>通过解构获得的 count:{{ count }}</h4>
      
        <button @click="getStore">按钮</button>
        <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
        <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
      </template>
      
      <script setup lang="ts">
      // 导入 pinia 中的 storeToRefs 方法
      import { storeToRefs } from 'pinia';
      // 导入 pinia 实例
      import { useMainStore } from '../store/index'
      
      // 实例化容器
      const mainStore = useMainStore()
      
      // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
      // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
      const { message1, message2, count } = storeToRefs(mainStore)
      
      // 按钮点击事件
      const getStore = () => {
        console.log(message1 + " " + message2 + " " + count);
        mainStore.count++
      }
      
      // 自定义的 count 加法方法
      const addCount = () => {
        **// $patch 方法,可以直接修改 state 中的值
        mainStore.$patch({
          message1: '你好',
          message2: '菠萝',
          count: 66,
        })**
      }
      </script>
      
      <style scoped></style>
      

      在这里插入图片描述

  3. 使用方法三的语法应用某些更改确实很困难或成本很高: 任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。正因为如此,该 $patch 方法还接受一个函数来对这种难以用补丁对象应用的改变进行分组:

    <template>
      <h2>{{ message1 }}</h2>
      <h3>{{ message2 }}</h3>
      <h4>没有通过解构获得的 count:{{ mainStore.count }}</h4>
      <h4>通过解构获得的 count:{{ count }}</h4>
    
      <button @click="getStore">按钮</button>
      <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
      <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
    </template>
    
    <script setup lang="ts">
    // 导入 pinia 中的 storeToRefs 方法
    import { storeToRefs } from 'pinia';
    // 导入 pinia 实例
    import { useMainStore } from '../store/index'
    
    // 实例化容器
    const mainStore = useMainStore()
    
    // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
    // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
    const { message1, message2, count } = storeToRefs(mainStore)
    
    // 按钮点击事件
    const getStore = () => {
      console.log(message1 + " " + message2 + " " + count);
      mainStore.count++
    }
    
    // 自定义的 count 加法方法
    const addCount = () => {
      // mainStore.addCount()
    
      // 1、$patch 方法,可以直接修改 state 中的值
      // mainStore.$patch({
      //   message1: '你好',
      //   message2: '菠萝',
      //   count: 66,
      // })
    
      **// 2、$patch 方法,通过分组改变 state 中的值
      mainStore.$patch(state => {
        state.message1 += ' Hello'
        state.message2 += ' Pinia'
        state.count++
      })**
    }
    </script>
    
    <style scoped></style>
    

    在这里插入图片描述

您也可以完全自由地设置您想要的任何参数并返回任何内容。调用 actions 时,一切都会自动推断!

② 重置状态 $reset

  1. 上面我说过,pinia的state更新的时候会有历史记录,即时间旅行,如果想要将数据重置到最开始更新数据的时候,pinia提供了一个方法:$reset

    <template>
      <h2>{{ message1 }}</h2>
      <h3>{{ message2 }}</h3>
      <h4>没有通过解构获得的 count:{{ mainStore.count }}</h4>
      <h4>通过解构获得的 count:{{ count }}</h4>
    
      <button @click="getStore">按钮</button>
      <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
      <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
      **<button @click="resetCount">重置 state**</**button>**
    </template>
    
    <script setup lang="ts">
    // 导入 pinia 中的 storeToRefs 方法
    import { storeToRefs } from 'pinia';
    // 导入 pinia 实例
    import { useMainStore } from '../store/index'
    
    // 实例化容器
    const mainStore = useMainStore()
    
    // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
    // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
    const { message1, message2, count } = storeToRefs(mainStore)
    
    // 按钮点击事件
    const getStore = () => {
      console.log(message1 + " " + message2 + " " + count);
      mainStore.count++
    }
    
    // 自定义的 count 加法方法
    const addCount = () => {
      // mainStore.addCount()
    
      // 1、$patch 方法,可以直接修改 state 中的值
      // mainStore.$patch({
      //   message1: '你好',
      //   message2: '菠萝',
      //   count: 66,
      // })
    
      // 2、$patch 方法,通过分组改变 state 中的值
      mainStore.$patch(state => {
        state.message1 += ' Hello'
        state.message2 += ' Pinia'
        state.count++
      })
    }
    
    **// 重置 count 数据的方法
    const resetCount = () => {
      mainStore.$reset()
    }**
    </script>
    
    <style scoped></style>
    

    在这里插入图片描述

③ 跨容器调用

  1. 在pinia中没有modules概念,可以在pinia中同时创建多个容器实例;可以在每一个容器中分别调用其他容器中的值,进行一些列的操作;

  2. 首先在src/store/index.ts文件中创建一个新的容器,在新的容器中可以在actions中,获取到其他容器实例,调用其中的state值:

    import { defineStore } from 'pinia' // 导入 pinia 中的功能模块
    
    // 创建容器
    // 参数一:容器名
    // 参数二:容器的内容
    const useMainStore =  defineStore('main', {
      // pinia 状态管理的数据,通过箭头函数返回一个对象
      // 相当于 vue 中的 data 数据
      state: () => {
        return {
          message1: 'Hello',
          message2: 'Pinia',
          count: 1,
          number: 666
        }
      },
    
      // 相当于 vue 中的 computed 计算属性
      getters: {},
    
      // 相当于 vue 中的 methods 方法
      actions: {
        // 1、count 加法方法
        addCount() {
          this.count++
        }
      }
    })
    
    const useProjectStore =  defineStore('project', {
      // pinia 状态管理的数据,通过箭头函数返回一个对象
      // 相当于 vue 中的 data 数据
      state: () => {
        return {
          username: 'liangshuang',
          age: 21
        }
      },
    
      // 相当于 vue 中的 computed 计算属性
      getters: {},
    
      // 相当于 vue 中的 methods 方法
      actions: {
        // 1、age 加法方法
        addAge() {
          // 实例化 pinia 容器
          const mainState = useMainStore()
          this.age += this.age + mainState.count
        }
      }
    })
    
    // 导出容器
    export {
      useMainStore,
      useProjectStore
    }
    
  3. 在组件中可以有两种方法去调用pinia中跨容器调用的方法:

    • 方法一: 直接在标签中去调用容器中的方法

      <template>
        <h4>{{ age }}</h4>
        **<button @click="projectStore.addAge">模板跨容器调用</button>**
      </template>
      
      <script setup lang="ts">
      // 导入 pinia 中的 storeToRefs 方法
      import { storeToRefs } from 'pinia';
      // 导入 pinia 实例
      import { useMainStore, useProjectStore } from '../store/index'
      
      // 实例化容器
      const mainStore = useMainStore()
      const projectStore = useProjectStore()
      
      // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
      // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
      const { message1, message2, count, number } = storeToRefs(mainStore)
      const { username, **age** } = storeToRefs(projectStore)
      </script>
      
      <style scoped></style>
      

      在这里插入图片描述

    • 方法二: 自定义一个调用容器方法的函数

      <template>
        <h4>{{ age }}</h4>
        <button @click="projectStore.addAge">模板跨容器调用</button>
        **<button @click="addAge">自定义方法跨容器调用</button>**
      </template>
      
      <script setup lang="ts">
      // 导入 pinia 中的 storeToRefs 方法
      import { storeToRefs } from 'pinia';
      // 导入 pinia 实例
      import { useMainStore, useProjectStore } from '../store/index'
      
      // 实例化容器
      const mainStore = useMainStore()
      const projectStore = useProjectStore()
      
      // 体验通过解构获取 pinia 的 state,解构出来的值不是响应式的
      // 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
      const { message1, message2, count, number } = storeToRefs(mainStore)
      const { username, age } = storeToRefs(projectStore)
      
      **// 自定义的 age 加法方法
      const addAge = () => {
        projectStore.age += mainStore.number
      }**
      </script>
      
      <style scoped></style>
      

      在这里插入图片描述

④ actions 的操作

const changeStore = () => {
  // 方式四:逻辑比较多的时候可以封装到 actions 做处理
  // 封装好 actions 之后,直接调用
  mainStore.adds(10)
}
  • 封装 actions:

    // 类似与组件的 methods ,封装业务逻辑,修改 state 
    actions: {
      // 注意:不能使用箭头函数定义action,因为箭头函数绑定外部this
      adds(num: number) {      
        this.count = this.count + num
        this.foo++
        // 同样建议使用 $patch() 
        // this.$patch({})
        // this.Spatch(state = {……})
      }
    }
    

⑤ 注意点

像我上面的跨容器调用的时候,将每一个容器都放在同一个文件中了,最好的做法需要将每个容器单独写一个文件。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐