Vue3.0组合式API(六)-----数据共享pinia

一、基本操作

  • 功能:管理全局共享数据,pinia与vuex功能一样
  • 优势:pinia相对于vuex增加了对ts的支持,对响应式的支持,操作数据简直了

1.1 原理

  • State:存储共享的数据
  • Actions:可以包含任意异步操作,如axios,提交(dispatch),action自动commit给mutation,保证所有数据同步更新,其他方法,会使部分数据失真
  • Mutations:pinia已取消,vuex中会有
    在这里插入图片描述

1.2 安装、文件布局、调试

  • 安装pinia模块:npm install pinia --save
  • 文件布局
    • 文件main.ts
      import { createApp } from "vue";
      import App from "./App.vue";
      // 导入模块函数
      import { createPinia } from "pinia";
      // 加哪个模块就use哪个模块
      createApp(App).use(createPinia()).mount("#app");
      
      
    • 新建文件/store/index.ts
      import { defineStore } from "pinia";
      // defineStore函数:首参数是容器的id,必须唯一,
      // 最终会把所有容器挂载到根容器上,次参数:选项对象
      export const useStore = defineStore("main", {
        // 存储数据位置
        state: () => {return {};},
        // Getters可以认为是store的计算属性
        getters: {},
        // 类似于组件的methods,封装业务逻辑,修改state,
        // 内部不可写箭头函数,可用this调用本store内所有资源
        actions: {},
      });
      
  • 调试位置
    在这里插入图片描述

二、state及getters

2.1 state、getters定义

  • store/index.ts
    import { defineStore } from "pinia";
    
    export const useStore = defineStore("main", {
      // 存储数据位置
      state: () => {
        return {
          count: 0,
          name: "apple",
          isSold: true,
        };
      },
      // 特点:不可调用action方法,不会改变state的值,
      // 缓存:getter返回的值会根据他的依赖被缓存起来,
      //      且只有当它的依赖值发生改变才会被重新计算
      // return语句:方法内必须存在,否则无返回值
      getters: {
      	//
        // 单语句推荐写法:传入state,单语句箭头函数接的即为return语句
        printCount: (state) => state.count + 10,
        //
    	// 多语句不传参推荐写法:传入state,返回值ts自动类型推定
        printCount2(state) {
          // 此处写数据查询、聚合等操作逻辑
          // 必须有return语句
          return  state.count + num;
        },
        //
        // 多语句传参推荐写法
        printCount2(state) {
          // 函数体内可接收模板传入的参数
          return (num: number) => {
            // 必须有return语句,即为printCount2返回值
            return state.count + num;
          };
          // 上式也可写为return (num: number) => state.count + num;
        },
        //
      },
    });
    

2.2 模板中展示及调用

  • 文件/views/Shoppings.vue
    <template>
      <!-- 模板中读取state数据 -->
      <h1>产品名称:{{ name }}</h1>
      <h1>产品数量:{{ mainStore.count }}</h1>
      <!-- 模板中读取getters -->
      <h2>产品数量加10:{{ mainStore.printCount }}</h2>
      <h2>产品数量加10:{{ mainStore.printCount2(1) }}</h2>
    </template>
    
    <script lang="ts" setup>
    	// script标签setup语法糖,下面就不需要写setup(){}了
    	// 且默认导出所有定义的函数和变量
    	// 导入Store,默认导入的是index,所以也可以写"@/store"
    	import { useStore } from "@/store/index";
    	import { storeToRefs } from "pinia";
    	
    	// 调用函数:返回的其实是reactive包装过的store对象
    	const mainStore = useStore();
    	// 解构store内数据方法API,解构的每一个都是ref类型
    	const { name, isSold } = storeToRefs(mainStore);
    	
    	// script标签中读取数据
    	console.log(name.value);
    	console.log(mainStore.count);
    	
    	// 调用getters方法:printCount的返回值看其return语句
    	console.log(mainStore.printCount + 1);
    	console.log(mainStore.printCount2(2));
    </script>
    

三、修改state方法

3.1 组件标签中修改

  • views/Shopping.vue
    <template>
      <!-- 模板中读取数据 -->
      <h1>产品名称:{{ mainStore.name }}</h1>
      <h1>产品数量:{{ mainStore.count }}</h1>
      <button @click="method1">方法1</button>
      <button @click="method2">方法2</button>
      <button @click="method3(1)">方法3</button>
    </template>
    
    <script lang="ts" setup>
    	import { useStore } from "@/store/index";
    	
    	const mainStore = useStore();
    	
    	// 方法1:直接使用,mainStore本身就是reactive包装的
    	const method1 = () => {
    	  mainStore.count += 1;
    	  mainStore.name = "banana";
    	};
    	
    	// 方法2:如果批量修改多个数据,建议用$patch,渲染效率更高
    	const method2 = () => {
    	  mainStore.$patch((state) => {
    	    state.count++;
    	    state.name = "orange";
    	  });
    	};
    	
    	// 方法3:调用store中的actions,此处接收传入参数num
    	const method3 = (num: number) => mainStore.changestate(num);
    </script>
    
  • 方法3:store/index.ts中action写法
    ...
    actions: {
      changestate(num: number) {
        this.count += num;
        this.name = "pear";
        // 方法内也可用$patch批量修改: this.$patch(state=>{});
      },
    },
    ...
    

3.2 actions中异步操作

功能:处理异步操作,例如:axios,此处运用了上节的自定义请求接口getStuListAPI()

  • 文件store/index.ts
    import { defineStore } from "pinia";
    import Stu from "@/utils/api/api_stu";
    
    // 定义对象格式
    interface stuForm {
      id?: number;
      height?: number;
      birthday?: string;
      gender?: number;
    }
    
    export const useStore = defineStore("main", {
      state: () => {
        return {
          // ts语法:进行对象类型断言
          stus: [{}] as stuForm[],
        };
      },
    
      actions: {
      	// 异步方法写法:注意getStuApi不是js函数
        async getStuApi() {
          try {
            let res = await Stu.getStuListAPI();
            // 终端打印接收的数据
            console.log(res);
    
            this.stus.length = 0;
            this.stus.push(...res.data);
            // 终端打印state.stus
            console.log(this.stus);
          } catch (err) {
            console.log(err);
          }
        },
      },
    });
    

    执行契机:如果在组件的script中调用actions异步方法,组件会先执行同步方法,后异步
    解决方案:在script标签中加异步方法async function method() {try{await ...}...,在生命周期函数中运行onMounted(() => {method(); });

  • 组件调用写法
    <template>
      <!-- 模板中展示数据 -->
      <ul v-for="stu in mainStore.stus" :key="stu.id">
        <li>{{ stu.height }}</li>
      </ul>
    </template>
    
    <script lang="ts" setup>
      import { useStore } from "@/store/index";
    
      const mainStore = useStore();
      // 组件挂载前调用store的action方法更新state.stus
      mainStore.getStuApi();
    </script>
    
  • 效果
    在这里插入图片描述

跳转至vue总篇目录

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值