新一代状态管理工具 -- Pinia 上手指南

news2025/7/8 0:21:47

一:Pinia简介和五大优势

Pinia是vue生态里Vuex的替代者,一个全新的vue状态管理库。在Vue3成为正式版以后,尤雨溪强势推荐的项目就是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

2.启动项目:
在这里插入图片描述

npm install
npm run dev

3.pinia的安装:

npm install pinia

在这里插入图片描述

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

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

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

引入后,通过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:{}
})

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

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

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

state:()=>{
   return {
     helloPinia:'Hello Pinia!'
   }
},

这时候这个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>

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

<script setup lang="ts">
  import Hyy from "./components/Hyy.vue";
</script>

<template>
  <Hyy />
</template>

<style>
</style>

四: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>

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

\src\store\index.ts文件

state:()=>{
  return {
    helloWorld:'HelloWorld',
    count:0
  }
},

有了这个状态数据后,再回到\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>

写好后,我们把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>

然后把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>

做完这步后,就可以到浏览器中查看一下最终的实现效果。如果一切正常,你可以看到我们点击按钮后,两个组件的数据通过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>

我们可以把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>

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

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

import { storeToRefs } from "pinia";

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

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

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

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

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

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

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

\scr\components\CountButtton.vue

const handleClickPatch = () => {
    store.$patch({
        count:store.count + 2 
    })
}

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

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

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

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

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

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

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

因为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>
第三种:$patch加函数的形式修改状态数据

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

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

const handleClickMethod = ()=> {
    store.$patch((state)=>{
        state.count ++
        state.helloPinia = state.helloPinia === 'Hello Pinia!' ? 'Hello World!' : 'Hello Pinia!' 
    })
}

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

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

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

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

actions: {
    changeState(){
        this.count++
        this.helloPinia = 'change helloPinia!!!'
    }
}

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

const handleClickActions = ()=>{
    store.changeState()
}

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

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

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

六:Pinia中的Getters使用

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

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

state:() => { 
    return {
        helloPinia: 'Hello Pinia!',
        count: 0,
        phone:'17808098401'
    } 
},

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

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

然后到\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')
     }
 },

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

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

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

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

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

当电话号码改变时,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')
    }
},

因为我们使用的是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: {
    }
})

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

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

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

actions: {
    changeState(){
        this.count++
        this.helloPinia = 'change helloPinia!!!'
    },
    getList(){
        console.log(hyyStore().list)
    }
}

为了方便学习,这里给出\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)
        }
    }
})

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405430.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5个前端练手项目(html css js canvas)

前言&#xff1a; 首先祝大家端午节快乐。本篇文章有5个练手项目 对于刚学完前端三剑客的你们。应该是一个很好的实践 目录 &#x1f969;.跑马灯 1.1效果图&#xff1a; 1.2思路解析 1.3源码 &#x1f367;.彩虹爱心 2.1效果图 2.2思路解析 2.3源码 &#x1f32e;.闹钟…

vue中this.$set()的用法

1、this.$set()的作用 向响应式对象中添加一个属性&#xff0c;并确保这个新属性同样是响应式的&#xff0c;且触发视图更新。 this.$set()用于向响应式对象上添加新属性&#xff0c;因为 Vue 无法探测普通的新增属性。 简单来说&#xff1a;就是我们在methods中给数据添加了一…

尚品汇项目笔记

尚品汇项目笔记git代码地址前端Vue核心1、vue文件目录分析2、项目配置3、组件页面样式4、清除vue页面默认的样式5、pages文件夹6、footer组件显示与隐藏7、路由传参8、多次执行相同的push问题9、定义全局组件10、代码改变时实现页面自动刷新11、Home首页其它组件12、封装axios1…

微信小程序实现分享至朋友圈的功能

微信小程序实现分享至朋友圈的功能 微信小程序从基础库 2.11.3 开始&#xff0c;可将小程序页面分享到朋友圈。适用于内容型页面的分享&#xff0c;不适用于有较多交互的页面分享。 1 设置分享状态 小程序页面默认不可被分享到朋友圈&#xff0c;开发者需主动设置“分享到朋友…

HBuilder X的下载与使用(详细步骤)

一、HBuilder X的下载 这里我们前往HBuilder下载官网地址&#xff1a;https://www.dcloud.io/进入官网后&#xff0c;我们可以看到HBuilder目前有两个版本&#xff0c;一个是windows版&#xff0c;一个是mac版。下载一个自己电脑适合的版本&#xff0c;这里我下载步骤用的是wi…

【Ajax】如何通过axios发起Ajax请求

✍️ 作者简介: 前端新手学习中。 &#x1f482; 作者主页: 作者主页查看更多前端教学 &#x1f393; 专栏分享&#xff1a;css重难点教学 Node.js教学 从头开始学习 ajax学习 文章目录axios  什么是axios  axios发起GET请求  axios发起POST请求  直接使用axios发起get…

JS解构赋值

一、前言 解构赋值语法是一种 Javascript 表达式。通过解构赋值&#xff0c;可以将属性/值从对象/数组中取出&#xff0c;赋值给其他变量。本文将讨论解构赋值的作用与其用法。 目录 一、前言 二、用途 三、数组的解构 1.变量声明并且赋值时的解构 2.默认值 3.剩余数组赋值…

js字符串转换为对象格式的3种方法

背景&#xff1a; js字符串转换为对象格式&#xff0c;一般都会想到JSON.parse()&#xff0c;但数据不是标准的 JSON 格式的时候会解析出错&#xff0c;这时候就可以使用eval() 函数、new Function()方法来转换。 常用3种将字符串string转为json对象 方法&#xff1a; var str…

如何解决 npm ERR! Cannot read properties of null (reading ‘pickAlgorithm‘)报错问题

1、问题描述&#xff1a; 在vue项目中&#xff0c;当我们在终端使用指令&#xff1a;npm install 下载 node_modules (节点_模块) 时出现报错的情况。 node_modules是安装node后用来存放用包管理工具下载安装的包的文件夹。比如webpack、gulp、grunt这些工具。 主要是这个原因&…

基于Web的疫情防控管理系统

目 录 1 绪论........................................................................................................... 1 1.1 研究背景..................................................................................................................... 1 1…

前端如何调用后端接口进行数据交互(极简)

前端调用后端接口&#xff0c;获得数据并渲染 一、介绍 一个完善的系统&#xff0c;前后端交互是必不可少的&#xff0c;这个过程可以分成下面几步&#xff1a; 前端向后端发起请求后端接口接收前端的参数后&#xff0c;开始层层调用方法处理数据后端将最终数据返回给前端接…

vue2和vue3的区别(由浅入深)

前言 vue2和vu3之前的区别&#xff0c;一直以来是面试必考题目&#xff0c;如何回答&#xff0c;回答的层次决定了面试者的对于vue2&#xff0c;3的理解&#xff0c;以及对于vue3目前稳定版本发展的方向的了解&#xff0c;即考察使用程度&#xff0c;又考察了学习能力&#xf…

babel安装失败/报错详细解决方案报以下错误: core-js@2.6.12: core-js@<3.23.3 is no longer maintained and not recommended

babel安装失败/报错详细解决方案 **问题&#xff1a;**在VSCode中执行命令 npm install --global babel-cli 报以下错误&#xff1a; core-js2.6.12: core-js❤️.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V…

Vue路由传参,页面刷新后参数丢失原因与解决方法

vue路由传参方法 在编写vue项目时&#xff0c;时常会使用路由在不同页面中传递参数&#xff0c;常见使用方式如下&#xff1a; this.$router.push({path: "/test",query: {a: 1,b: 2} }) 这样我们就传递了两个参数&#xff0c;在 /test 页面 就可以接收这两个参数…

Python 万能代码模版:爬虫代码篇

你好&#xff0c;我是悦创。 很多同学一听到 Python 或编程语言&#xff0c;可能条件反射就会觉得“很难”。但今天的 Python 课程是个例外&#xff0c;因为今天讲的 **Python 技能&#xff0c;不需要你懂计算机原理&#xff0c;也不需要你理解复杂的编程模式。**即使是非开发…

Vite打包性能优化之开启Gzip压缩

在使用 vite 进行项目打包时&#xff0c;默认已经帮我们做了一些优化工作&#xff0c;比如代码的压缩&#xff0c;分包等等。除此之外&#xff0c;我们还有一些可选的优化策略&#xff0c;比如使用 CDN &#xff0c;开启 Gzip 压缩等。本文会介绍在 vite 中使用插件来开启 Gzip…

vue-router路由懒加载

路由懒加载指的是打包部署时将资源按照对应的页面进行划分&#xff0c;需要的时候加载对应的页面资源&#xff0c;而不是把所有的页面资源打包部署到一块。避免不必要资源加载。&#xff08;参考vue项目实现路由按需加载(路由懒加载)的3种方式_小胖梅的博客-CSDN博客_vue懒加载…

原生微信小程序/uniapp使用空格占位符无效解决方法

最近碰到一个需求&#xff0c;在一个<text>文本中的前后添加空格占位符&#xff0c;总所周知&#xff0c;我并不会前端&#xff0c;于是我查看了原生微信小程序以及uniapp官方文档&#xff0c;得到了以下答案&#xff1a; 原生微信小程序官方文档 uniapp官方文档 从文档…

毕业设计-基于微信小程序的校园二手闲置物品交易系统

目录 前言 课题背景与简介 实现设计思路 一、需求分析 二、微信小程序云开发框架及其设计流程 三、功能测试以及性能测试 四、总结 实现效果样例 更多帮助 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要…

如何创建一个vue项目(详细步骤)

一、环境准备 1、安装 node.js 下载地址&#xff1a;https://nodejs.org/en/ 2、检查是否安装成功&#xff1a;输出版本号说明安装成功 二、搭建 vue 环境 1、全局安装脚手架 vue-cli 在命令行输入&#xff1a; npm install vue-cli -g &#xff08;vue-lcli2) npm install…