官网: https://pinia.vuejs.org/
Pinia的使用(在和TypeScript的环境下
1. 创建项目
1.1 应用系统定制开发脚手架搭建
npm init vite@latest
应用系统定制开发后面操作见图示
1.2 安装pinia
该笔记, pinia基于版本2.0.11
npm i pinia@2.0.11
或者 yarn add pinia@2.0.11
2. Pinia - Store
2.1 创建Store
应用系统定制开发在入口文件main.ts
中:
import { createApp } from "vue";import App from "./App.vue";// 引入piniaimport { createPinia } from "pinia";// 创建 Pinia 实例const pinia = createPinia();const app = createApp(App);// 挂载到 Vue 根实例app.use(pinia);app.mount("#app");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
2.2 Store详讲
在src下, 应用系统定制开发新建文件夹store
, 再新建index.ts
在index.ts中:
/** * 应用系统定制开发一般在容器中做这4件事 * 1. 应用系统定制开发定义容器并导出 * 2. 使用容器中的state * 3. 修改容器中的state * 4. 使用容器中的action */import { defineStore } from "pinia";/** * 1. 定义容器并导出 * 参数一: 容器ID, 唯一, 将来 Pinia 会把所有的容器挂载到根容器 * 参数二: 选项对象 * 返回值: 函数, 调用的时候要空参调用, 返回容器实例 */export const mainStore = defineStore('main', { /** * 类似组件的 data, 用于存储全局的的状态 * 注意: * 1.必须是函数, 为了在服务端渲染的时候避免交叉请求导致的数据交叉污染 * 2.必须是箭头函数, 为了更好的 TS 类型推导 */ state: () => { return { count: 100, foo: 'bar', age: 18 } }, /** * 类似组件的 computed, 用来封装计算属性, 具有缓存特性 */ getters: { }, /** * 类似组件的 methods, 封装业务逻辑, 修改state * 注意: 里面的函数不能定义成箭头函数(函数体中会用到this) */ actions: { }})
- 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
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
2.3 使用store中的状态
2.3.1 简单访问store状态
把components/HelloWorld.vue
中的代码清空, 加入以下代码
<template> <div v-text="mainStoreI.count"></div></template><script lang="ts" setup> import {mainStore} from '../store' const mainStoreI = mainStore() console.log(mainStoreI.count);</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2.3.2 访问及简单修改store(标准操作)
但是上面的访问未免过于麻烦, 使用 count、foo 前面还要加 mainStoreI , 如果直接采用解构的方式, 会导致数据不是响应式的, 具体解决方式如下:
import { storeToRefs } from ‘pinia’;
<template> <div v-text="mainStoreI.count"></div> <hr> <p>count: {{ count }}</p> <p>foo: {{ foo }}</p> <p>age: {{ age }}</p> <button @click="handleClick">修改count数据</button></template><script lang="ts" setup> import {mainStore} from '../store' import { storeToRefs } from 'pinia'; const mainStoreI = mainStore() const {count, foo, age} = storeToRefs(mainStoreI) /** 修改store中的数据 */ const handleClick = () => { // 修改单个数据,方式一 // count.value++ // 修改单个数据,方式二 mainStoreI.count++ }</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
2.4 store - $patch 批量简单修改
多个数据修改,建议使用
$patch
批量更新,不单纯是写法优化,还有性能的优化
/** 修改store中的数据 */ const handleClick = () => { // 哪些数据项需要修改就写数据项 mainStoreI.$patch({ count: ++mainStoreI.count, foo: 'hello', }) }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
2.5 $patch怎么更新数组?
方式一: 利用ES6展开运算符
const handleClick = () => { mainStoreI.$patch({ // 更新数组 arr: [...mainStoreI.arr, 4] })}
- 1
- 2
- 3
- 4
- 5
- 6
方式二: $patch可以接收一个函数(推荐)
const handleClick = () => { // 给$patch传入一个函数,函数体中修改数据项 // 形参state即为容器 mainStoreI.$patch((state) = { state.count++; state.foo = 'hello'; state.arr.push(4) })}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.6 总结: 修改状态数据的四种方式
3. Pinia - actions
- 修改 Store 状态时, 如果逻辑较多, 可以借助 actions
- actions 中也可以使用 $patch, 见下面代码
注意:
- actions 中的函数, 不能定义成箭头函数
- 因为箭头函数中没有this, 在运行时, 会向外部的作用域找
src\store\index.ts
/** * 类似组件的 methods, 封装业务逻辑, 修改state */actions: { changeState(num: number): void { // this访问当前容器的实例 this.count += num this.foo='你好啊' this.arr.push(555) // 这里也可以使用$patch // this.$patch({}) // this.$patch(state => {}) }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
业务代码<script>中:
/** 修改store中的数据 */const handleClick = () => { // 当逻辑较多时,可以封装到actions中处理 mainStoreI.changeState(10)}
- 1
- 2
- 3
- 4
- 5
4. Pinia - getters
-
具有缓存特性
-
getters的定义有两种
-
接受一个形参, 代表容器状态实例(数据)
count10 (state) { state.count + 10}
- 1
-
不使用形参, 函数体中使用
this
, 必须手动指定返回值类型原因: 无法推导this的类型, 会导致编译报错, 需手动指定返回值类型
count10 (): number { this.count + 10}
- 1
- 2
- 3
-
(不推荐) 既使用state, 也使用this, 这个时候可以不手动指定返回值类型
这种写法怪怪的, 写了形参不用
count10 (state){ this.count + 10}
- 1
- 2
- 3
-
定义:
export const mainStore = defineStore('main', { state: () => { return { count: 100, foo: 'bar', age: 18, arr:[99, 55] } }, /** * 类似组件的 computed, 用来封装计算属性, 具有缓存特性 */ getters: { // 每次使用的 count10 都是在 count 的基础上加10 count10 (state) { console.log('count10 调用了'); return state.count+10 } }})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
如图, count10 访问了3次, 但是由于缓存, 实际 getters 只运行了一次:
5. Store相互调用
如果存在相互调用的情况, 和在业务组件中使用一致
- 在A中导入B
- 实例化
- 调用B中的方法等…