目录
一、基本操作
- 功能:管理全局共享数据,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: {}, });
- 文件main.ts
- 调试位置
二、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>
- 效果