前言
- 记录Vue3与Pinia的基本用法
- 实现简单的数据状态控制
一、前期准备
二、使用步骤
1.使用vite创建vue3项目
npm init vite@latest
- 选择vue — vue-ts
- pnpm i 安装依赖
- pnpm run dev 启动初始化项目
安装pinia :pnpm i pinia
2.初始化pinia
- 修改main.ts
import { createApp } from "vue";
import { createPinia } from "pinia";
import "./style.css";
import App from "./App.vue";
//创建 app 实例
const app = createApp(App);
// 创建 pinia 实例
const pinia = createPinia();
// 使用pinia实例
app.use(pinia);
// 挂载app
app.mount("#app");
- src下创建store/index.ts
基本框架:
import { defineStore } from "pinia";
export const useFirstStore = defineStore("first", {
actions: {},
getters: {},
state: () => {
return {};
},
});
- 进一步按需修改:
import { defineStore } from "pinia";
// 1.定义容器
// 2.使用容器的state
// 3.修改state
// 4.容器中的action使用
/**
* 参数1:容器的ID(唯一),Pinia会将所有的容器挂载到根容器
* 参数2:选项对象
* 返回值是一个函数
**/
export const useMainStore = defineStore("main", {
/**
* state
* 类似于组件的data,存储全局状态
* 1.必须是函数(箭头函数),箭头函数有助于ts类型推导。
* 使用函数可以防止在服务端渲染的时候交叉请求导致数据状态污染
**/
state: () => {
return {
count: 1,
foo: "2",
arr: [1, 2],
};
},
/**
* getters
* 类似于组件的computed,用来封装计算属性,有缓存功能(如在页面中调用三次,如果数值无变化则只执行一次)
**/
getters: {
// ts指定返回值类型
count10(): number {
console.log("相当于computed,一来就调用");
return this.count++;
},
// 使用state里的数据,指定数据源
// count11(state) {
// return state.count++;
// },
},
/**
* actions
* 类似于组件的methods,封装业务逻辑,修改state中数据的状态
* actions中要使用this,所以不能使用箭头函数定义
* (HelloWorld组件中的方式4)
**/
actions: {
// 可以在使用本store(useMainStore)的时候调用actions中的方法来控制state状态
// 定义num:number类型,可以接收从页面传来的值
changeState(num: number) {
// 通过this直接访问state中的数据
// 单次修改
this.count += num;
this.foo = "zwt2";
this.arr.push(666);
// 也支持同时修改多个参数
/* // 对象方式
this.$patch({
count: this.count + 9,
foo: this.foo + 12,
}); */
/* // 函数方式
this.$patch(state => {
this.count++,
this.foo + 12,
}); */
},
},
});
3.组件使用
- 修改HelloWord.vue为
- 四个button包括不同的用法以及注意事项
<template>
<div style="text-align: left">
<h2>Pinia Test</h2>
<ul>
<li v-for="b in buttonContent">{{ b.id }}——{{ b.content }}</li>
</ul>
普通方式获取count:{{ mainStore.count }}
<hr />
使用storeToRefs获得响应式数据:{{ count }}
<hr />
<button @click="add">Button1</button>
{{ count }}
<hr />
<button @click="addSome">Button2</button>
参数1: {{ count }}—— 参数2: {{ foo }}
<hr />
<button @click="addArr">Button3</button>
参数1: {{ count }}—— 参数2: {{ foo }}—— 参数3:{{ arr }}
<hr />
<button @click="changeInActions">Button4</button>
参数1: {{ count }}—— 参数2: {{ foo }}—— 参数3:{{ arr }}
<hr />
<h2>{{ mainStore.count10 }}</h2>
<!-- <h2>{{ mainStore.count11 }}</h2> -->
</div>
</template>
<script setup lang="ts">
import { useMainStore } from "../store";
import { storeToRefs } from "pinia";
import { ref } from "vue";
// 各类button对应的内容
const buttonContent = ref([
{
id: "button1",
content: "修改state单个数据(用storeToRefs获得响应式数据)",
},
{ id: "button2", content: "使用$patch修改state多个数据" },
{ id: "button3", content: "使用$patch函数方式直接修改state数据" },
{ id: "button4", content: "使用封装在actions中的方法修改state数据" },
]);
// 初始化实例
const mainStore = useMainStore();
console.log(mainStore);
// Pinia把state的数据做了reactive处理,解构赋值成响应式数据要借用toRefs
// 此处count被解构出来的是一个ref对象,需要使用count.value访问
const { count, foo, arr } = storeToRefs(mainStore);
// 方式一 最简单的state状态数据修改,单个数据
const add = () => {
// console.log(count.value);
count.value++;
};
//方式二 对state中的多个数进行修改,使用$patch(有内部优化,批量更新系)
// 比较简单的多个数据修改
const addSome = () => {
mainStore.$patch({
count: count.value + 9,
foo: foo.value + 12,
});
};
// 方式三 将$patch写成一个函数,可以对state中的数组进行修改(推荐)
// 比较复杂的多个数据修改(数组等)
// 通过指定添加参数state,写成一个函数可以直接对里面的数据进行修改
// 无需加上 .value,直接使用state.x=""修改
const addArr = () => {
mainStore.$patch((state) => {
state.count++;
state.foo = "添加数组成功";
state.arr.push(8);
});
};
// 方式4 逻辑较多的时候可以使用封装在actions中的changeState方法(index中)
const changeInActions = () => {
mainStore.changeState(12);
};
</script>
<style scoped>
button {
background-color: #bfa;
}
</style>
4.效果展示
总结
- 要多思考各个数据逻辑之间的调用关系
- ts语法注意类型转换
- storeToRefs可将state中的数据变为响应式数据在模板中直接使用
- 更多内容见注释详解
本文含有隐藏内容,请 开通VIP 后查看