定制开发小程序新一代状态管理工具 -- Pinia 上手指南

一:定制开发小程序简介和五大优势

Pinia是vue生态里Vuex的替代者,定制开发小程序一个全新的vue定制开发小程序状态管理库。定制开发小程序在成为正式版以后,定制开发小程序尤雨溪强势推荐的项目就是Pinia。
定制开发小程序那先来看看Pinia比Vuex好的地方,也就是Pinia定制开发小程序的五大优势。

  1. 可以对Vue2和Vue3定制开发小程序做到很好的支持,定制开发小程序也就是老项目也可以使用Pinia。
  2. 抛弃了Mutations的操作,只有state、getters和actions.定制开发小程序极大的简化了状态管理库的使用,定制开发小程序让代码编写更加容易直观。
  3. 定制开发小程序不需要嵌套模块,符合Vue3的Composition api ,定制开发小程序让代码更加扁平化。
  4. 完整的TypeScript支持。Vue3定制开发小程序版本的一大优势就是对TypeScript的支持,所以Pinia定制开发小程序也做到了完整的支持。如果你对Vuex定制开发小程序很熟悉的化,一定知道Vuex对TS定制开发小程序的语法支持不是完整的(定制开发小程序经常被吐槽)。
  5. 定制开发小程序代码更加简洁,定制开发小程序可以实现很好的代码自动分割。Vue2的时代,定制开发小程序写代码需要来回翻滚屏幕屏幕找变量,非常的麻烦,Vue3的Composition api完美了解决这个问题。 可以实现代码自动分割,pinia也同样继承了这个优点。

如果你说这五点有点太多了,记不住。可以简单总结Pinia的优势就是,更加简洁的语法,完美支持Vue3的Composition api 和 对TypesCcript的完美支持。这些优势和的强烈推荐。个人觉得很快Pinia就会完全取代Vuex,成为最适合Vue3的状态管理库。

二:Pinia开发环境安装

这里我就用Vite来创建一个Vue3项目为例。

1.使用Vite就需要先初始化vite:

npm init vite@latest
  • 1

2.启动项目:

npm installnpm run dev
  • 1
  • 2

3.pinia的安装:

npm install pinia
  • 1

可以看到安装的pinia最新版本是2.0.12

三:用Pinia的方式创建一个store

1.在main.ts文件里引入Pinia
import { createPinia } from 'pinia'
  • 1

引入后,通过createPinia( )方法,得到pinia的实例,然后将Pinia挂载到Vue根实例上。

2.创建store状态管理库

直接在/src目录下,新建一个store文件夹。有了文件夹之后,再创建一个index.ts文件。

这个文件里的代码,我们一般只做三件事:

  1. 定义状态容器(仓库)
  2. 修改容器(仓库)中的 state
  3. 仓库中的 action 的使用

第一步:定义状态容器(仓库)

import { defineStore} from 'pinia'export const mainStore = defineStore('main',{  state:()=>{    return {}  },  getters:{},  actions:{}})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

写完这段代码,你会感觉这个很像一个Vue的小组件,这也算是Pinia的一个优点。

  • defineStore( ) 方法的第一个参数:相当于为容器起一个名字。注意:这里的名字必须唯一,不能重复。
  • defineStore( ) 方法的第二个参数:可以简单理解为一个配置对象,里边是对容器仓库的配置说明。当然这种说明是以对象的形式。
  • state 属性: 用来存储全局的状态的,这里边定义的,就可以是为SPA里全局的状态了。
  • getters属性: 用来监视或者说是计算状态的变化的,有缓存的功能。
  • actions属性: 对state里数据变化的业务逻辑,需求不同,编写逻辑不同。说白了就是修改state全局状态数据的。

第二步:我们在Store里定义一个State,我们这里就写Hello Pinia!。

state:()=>{   return {     helloPinia:'Hello Pinia!'   }},
  • 1
  • 2
  • 3
  • 4
  • 5

这时候这个helloPinia就是全局的状态数据,是每个页面和组件都可以通过Pinia方法读取到的。

3.在vue3组件里读取Store数据

在\src\components里,新建一个Hyy.vue的组件。代码如下:

先引入mainStore,然后通过mainStore得到store实例,就可以在组件里调用store里的state定义的状态数据了

<template>  <div>      <h2 class="">{{ store.helloPinia}}</h2>  </div></template><script lang="ts">import { mainStore } from "../store/index";export default{  setup(){      const store = mainStore();            return{          store,      }  }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

写好这个组件后,到App.vue里引入,就可以使用了:

<script setup lang="ts">  import Hyy from "./components/Hyy.vue";</script><template>  <Hyy /></template><style></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四:Pinia改变状态数据和注意事项

1.新建组件,实现状态数据的改变

为了演示数据仓库的概念,新建一个组件。然后在一个组件里修改状态数据,看看另一个组件中的数据是否会改变。

在\components\文件夹下新建一个文件CountButton.vue。

<template>    <h2 class="">{{ store.helloPinia }}</h2></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        return{            store,        }    }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

因为这里要做的是一个可以计数的组件,所以先到\store\index.ts的state属性中,增加一个状态数据count : 0。

\src\store\index.ts文件

state:()=>{  return {    helloWorld:'HelloWorld',    count:0  }},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

有了这个状态数据后,再回到\components\CountButton.vue文件里,增加button和对应的业务逻辑(注意这里的业务逻辑就是修改状态数据)。代码如下:

<template>    <div>        <button @click="handleClick">点击增加</button>    </div></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        const handleClick = () => {            store.count ++        }        return{            store,            handleClick        }    }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

写好后,我们把count显示再Hyy.vue组件里。

\src\components\Hyy.vue

<template>    <div>        <h2>{{ store.helloPinia }}</h2>        <h2>{{ store.count }}</h2>    </div></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        return{            store,        }    }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

然后把CountButton加入到App.vue页面中。

<script setup lang="ts">  import Hyy from "./components/Hyy.vue";  import CountButton from "./components/CountButton.vue";</script><template>  <Hyy />  <CountButton /></template><style></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

做完这步后,就可以到浏览器中查看一下最终的实现效果。如果一切正常,你可以看到我们点击按钮后,两个组件的数据通过Pinia的状态管理,已经可以实现联动了。

注意:别踩了结构的坑

我在学习的时候发现了这样一个坑,在这里也和大家分享一下。希望小伙伴们不要踩坑。看下面的代码,我们是否可以简化一点

<template>    <div>        <h2>{{ store.helloPinia }}</h2>        <h2>{{ store.count }}</h2>    </div></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        return{            store,        }    }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们可以把store进行解构,然后直接template中直接这样读出数据。

<template>    <div>        <h2>{{ store.helloPinia }}</h2>        <h2>{{ store.count }}</h2>                <hr/>        <h2>{{ helloPinia }}</h2>        <h2>{{ count }}</h2>    </div></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        const {helloPinia,count} = store;        return{            store,        }    }}</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

这样看似简单,但通过解构的数据,只有一次作用,不是响应式数据(这就是我踩的坑了)。也就是说当你改变数据状态时,解构的状态数据不会发生变化。我们这时候再点击增加按钮,可以看到只有没结构的数据发生了变化。

于是我开始查找官方文档,显然Pinia团队也发现了这个问题,提供了storeToRefs( )方法。这个方法Pinia中,所以我们先用import引入。

import { storeToRefs } from "pinia";
  • 1

有了storeToRefs( )方法后,就可以在解构的代码中,对store使用方法了。其实这时候就是把解构出来的数据作了ref响应式代理。所以数据拥有了响应式能力。

const { helloWorld, count } = storeToRefs(store);
  • 1

这时候再到浏览器中测试一下,就一切正常了。补充:其实在Vuex中,直接解构数据也是不可以的。

五:Pinia修改状态数据的多种方式

上面已经初步讲解了状态数据的修改,非常简单。但这只是数据修改的一种方式,还有三种方式。

第二种:使用$patch修改多条数据

接着上面编写的CountButton.vue 组件,我们再编写一个方法handleClickPatch( )这个方法。我们采用Pinia中的$patch的方式编写。

\scr\components\CountButtton.vue

const handleClickPatch = () => {    store.$patch({        count:store.count + 2     })}
  • 1
  • 2
  • 3
  • 4
  • 5

然后在里添加一个按钮,点击后执行这个方法。

<button @click="handleClickPatch">点击增加 - patch</button>
  • 1

当然我在修改单条数据的时候,我喜欢这种直接修改的方式store.count++,因为足够简单。但是如果你同时修改多条数据,这里建议你使用$patch的方法。

比如现在我们点击按钮时,同时修改状态数据helloPinia,就可以写成这种方式:

const handleClickPatch = () => {    store.$patch({        count:store.count + 2,        helloPinia:store.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!'     })}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那你说我在handleClick里直接写两行代码,是不是也可以实现这样的效果。通过代码测试,是可以实现的。哪为什么还要用$patch来做?

const handleClick = () => {    store.count ++    store.helloPinia = store.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!'}
  • 1
  • 2
  • 3
  • 4

因为Pinia的官方网站,已经明确表示$ patch的方式是经过优化的,会加快修改速度,对程序的性能有很大的好处。所以如果你是多条数据同时更新状态数据,推荐使用$patch方式更新。

完整代码:

<template>    <div>        <button @click="handleClick">点击增加</button>        <button @click="handleClickPatch">点击增加 - patch</button>    </div></template><script lang="ts">import { mainStore } from "../store/index";export default{    setup(){        const store = mainStore();        const handleClick = () => {            store.count ++            store.helloPinia = store.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!'        }        const handleClickPatch = () => {            store.$patch({                count:store.count + 2,                helloPinia:store.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!'             })        }        return{            store,            handleClick,            handleClickPatch        }    }}</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
  • 27
  • 28
  • 29
  • 30
  • 31
第三种:$patch加函数的形式修改状态数据

上面的$patch方法,我们的参数使用的是一个对象。还有一种方式是传递函数,这种方法适合复杂数据的修改,比如数组、对象的修改。

再编写一个方法handleClickMethod( ),然后传递一个箭头函数进去。

const handleClickMethod = ()=> {    store.$patch((state)=>{        state.count ++        state.helloPinia = state.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!'     })}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这时候的state就是store仓库里的state,所以我们可以直接在函数里改变任何状态数据的值。为了看到效果,我们再编写一个按钮,来执行这个方法。

<button @click="handleClickPatch">点击增加 - $patch+函数</button>
  • 1
第四种:在actions中写好逻辑,再调用actions

如果你有一个修改的过程非常复杂,你可以先在store里,定义好actions中的函数,然后在组件里再调用函数。

我们先到\src\store\index.ts文件里,在actions的地方编写一个changeState( )方法,用来改变数据状态。代码如下:

actions: {    changeState(){        this.count++        this.helloPinia = 'change helloPinia!!!'    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

有了这个changeState( )函数后,就可以在组件中调用这个函数来修改状态数据了。来到\src\components\CountButton.vue文件。编写一个新的方法handleClickActions( )方法。然后就可以用store调用changeState( )方法了。

const handleClickActions = ()=>{    store.changeState()}
  • 1
  • 2
  • 3

然后再加入一个按钮,调用这个方法就可以了。

<button @click="handleClickActions">点击增加 - actions</button>
  • 1

注意:在用actions的时候,不能使用箭头函数,因为箭头函数绑定是外部的this。这个小伙伴们需要注意一下就可以了。

六:Pinia中的Getters使用

1. 新增状态属性和编写Getters

先在\src\store\index.ts文件的state里增加一个phone的状态数据。

state:() => {     return {        helloPinia: 'Hello Pinia!',        count: 0,        phone:'17808098401'    } },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后再getters里编写一个方法,这个方法就是隐藏手机号中间四位的,隐藏的方法就是使用正则表达式替换。代码如下:

getters:{  phoneHidden(state){    return state.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')  }},
  • 1
  • 2
  • 3
  • 4
  • 5

然后到\src\components\Hyy.vue中直接显示隐藏号码显示:

这时候打开浏览器,可以看到电话号码已经被隐藏了。

2. Getters的缓存特性

Getters是有缓存特性的,现在我们的Hyy组件中调用了两次phoneHidden吧,这时我们在index.ts状态仓库里增加一个console.log('PhoneHidden被调用了’)。

 getters: {     phoneHidden(): string{         console.log('PhoneHidden被调用了')         return this.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')     } },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后回到浏览器中按F12打开查看Console面板,可以看到只显示了一次PhoneHidden被调用了,也变相说明了getters是有缓存的,虽然调用多次,但是值一样就不会被多次调用。

在\src\components\CountButton.vue文件下,新编写一个方法handleClickChangePhone。用来改变电话号码。

// 点击按钮的对应函数const handleClickChangePhone = () => {    store.phone = "17800000000";}
  • 1
  • 2
  • 3
  • 4

有了函数后,再编写一个按钮,触发这个函数,电话号码就变化了。

<button @click="handleClickChangePhone">Getter缓存</button>
  • 1

当电话号码改变时,Getters会自动工作,对应的phoneHidden方法也会随着调用一次,清除以前的数据缓存。

3. 关于this的使用

写完上面的小案例,相信你对Pinia的Getters的使用已经掌握了。这时候再回到\src\store\index.ts文件里。我们看到actions里是直接可以使用this关键字操作的。

那我们思考一个问题,在getters里可以用this进行操作吗?

答案时可以的,修改代码为下面的形式:

getters: {    phoneHidden():string{        return this.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')    }},
  • 1
  • 2
  • 3
  • 4
  • 5

因为我们使用的是TS,所以如果我们不传state, TypeScript是无法自动推到出来返回的数据类型的,所以这里我们要标明返回类型为String。就不会提示错误了。

总结:这节我们学习了Pinia中Getters的用法,它和Vue中的计算属性非常类似,但是拥有缓存属性。我们在编写Getters的时候,不仅可以传递state参数用来改变状态数据,还可以直接使用关键字this来改变数据。

七:Pinia中Store的互相调用

在上面代码中我们一直只使用了一个Store仓库,在真实项目中我们往往是有多个Store的。有多个Stroe时,就会涉及Store内部的互相调用问题。

第一步:新建一个Store仓库

在\src\store下新建一个Hyy.ts文件:

import { defineStore } from 'pinia'export const hyyStore = defineStore("hyyStore", {    state:() => {         return {            list:["黄黄","小黄","黄小黄"]        }     },    getters: {    },    actions: {    }})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这是一个非常简单的仓库,只有state(状态数据),需要注意的是ID要是唯一的。有了这个仓库后,就可以回到index.ts这个仓库中调用了。

第二步:先引入Hyy这个store。
import { hyyStore } from './hyy'
  • 1
第三步:然后在actions部分加一个getList( )方法。

这部分就写的很简单了,只是用console.log( )打印到控制台 上就可以了。

actions: {    changeState(){        this.count++        this.helloPinia = 'change helloPinia!!!'    },    getList(){        console.log(hyyStore().list)    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

为了方便学习,这里给出\src\store\index.ts的全部代码:

import { defineStore } from 'pinia'import { hyyStore } from './hyy'export const mainStore = defineStore("mian", {    state:() => {         return {            helloPinia: 'Hello Pinia!',            count: 0,            phone:'17808098401'        }     },    getters: {        phoneHidden():string{            return this.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')        }    },    actions: {        changeState(){            this.count++            this.helloPinia = 'change helloPinia!!!'        },        getList(){            console.log(hyyStore().list)        }    }})
  • 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

这样就实现了两个store中互相调用。

第四步:为了看到效果,我们依然来到\src\components\CountButton.vue这个文件里,写一个新的方法,就叫做getList( )。
const getList = () => {  store.getList();};
  • 1
  • 2
  • 3

有了getList( )方法后,在template部分,写一个按钮进行触发。

<button @click="getList">Pinia中store的相互调用</button>
  • 1

到浏览器中查看效果,按F12打开控制台,点击按钮后,可以看到跨Store的状态数据调用已经成功了。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发