Vue中的Pinia状态管理工具 | 一篇文章教会你全部使用细节

news2025/2/27 21:04:11

文章目录

  • Pinia状态管理
    • Pinia和Vuex的对比
    • Pinia基本使用
      • 🍤创建Pinia
      • 🍤创建Store
    • Pinia核心概念State
      • 🍟state基本使用
      • 🍟state其他操作
    • Pinia核心Getters
      • 🍕getters基本使用
      • 🍕getters其他操作
    • Pinia核心Actions
      • 🥧Actions基本使用
      • 🥧Actions异步操作

Pinia状态管理

Pinia和Vuex的对比

Pinia(发音为/piːnjʌ/,如英语中的“peenya”)是最接近piña(西班牙语中的菠萝)的词

Pinia开始于大概2019年,最初是作为一个实验为Vue重新设计状态管理,让它用起来适合组合式API(Composition API)。

从那时到现在,最初的设计原则依然是相同的,并且目前同时兼容Vue2、Vue3,也并不要求你使用Composition API;

Pinia本质上依然是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样);

那么我们不是已经有Vuex了吗?为什么还要用Pinia呢?

Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法;

最终,团队意识到Pinia已经实现了Vuex5中大部分内容,所以最终决定用Pinia来替代Vuex;

与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API

最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持;

和Vuex相比,Pinia有很多的优势

优势一: mutations 不再存在:

  • 他们经常被认为是非常冗长;
  • 他们最初带来了 devtools 集成,但这不再是问题;

优势二: 更友好的TypeScript支持,Vuex之前对TS的支持很不友好;

优势三: 不再有modules的嵌套结构:

  • 你可以灵活使用每一个store,它们是通过扁平化的方式来相互使用的;

优势四: 也不再有命名空间的概念,不需要记住它们的复杂关系;

在这里插入图片描述

Pinia基本使用

🍤创建Pinia

使用Pinia之前,我们需要先对其进行安装

yarn add pinia

npm install pinia

使用pinia我们需要在单独的js文件中创建一个pinia, 并且在main.js中将其注册, 如下:

这样我们项目中就已经存在pinia了

import { createPinia } from "pinia";

// 创建pinia
const pinia = createPinia()

// 导出pinia
export default pinia
import { createApp } from 'vue'
import App from './App.vue'

// 导入pinia
import pinia from './stores'

const app = createApp(App)

// 注册pinia
app.use(pinia)
app.mount('#app')

🍤创建Store

什么是Store?

一个 Store (如 Pinia)是一个实体,它会持有为绑定到你组件树的状态和业务逻辑,也就是保存了全局的状态;

它有点像始终存在,并且每个人都可以读取和写入的组件;

你可以在你的应用程序中定义任意数量的Store来管理你的状态;

Store有三个核心概念(接下来会一一讲到)

state、getters、actions;

等同于组件的data、computed、methods;

一旦 store 被实例化,你就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性

定义一个Store

Store 是使用 defineStore() 定义的, 我们一般都会在一个单独的js的文件创建store, 不同组件的数据, 我们会定义在不同的js文件中创建不同的store

由于pinia中可以定义多个store, 所以每一个store它都需要一个唯一名称,作为第一个参数传递;

// 定义关于counter的store
import { defineStore } from "pinia"

// 调用defineStore定义store, defineStore返回一个函数
const useCounter = defineStore("counter", {
  state: () => ({
    counter: 101
  })
})

// 将useCounter函数导出
export default useCounter

第一个参数 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools

defineStore()返回的函数统一使用useXXX作为命名方案, 且XXX一般就使用传入的id,这是约定的规范

调用defineStore()返回的函数才会创建store


Store在它被使用之前是不会创建的,我们可以通过调用use函数来使用Store

<template>
  <!-- 展示counterStore.counter的状态 -->
  <h2>{{ counterStore.counter }}</h2>
</template>

<script setup>
  // 导入我们自定义关于counter的store
  import useCounter from '../stores/counter';

  // 调用函数才会创建store, 不调用不会创建
  const counterStore = useCounter()
</script>

注意Store获取到后, 如果我们想要对其解构, 不能直接解构,直接解构的话会失去响应式

为了从 Store 中提取属性同时保持其响应式我们有两种方式

  • 方式一: 解构时包裹一层toRefs

  • 方式二: pinia给我们提供了一个方法, 使用storeToRefs()方法可以保持数据的响应式。

方式一

<script setup>
  import { toRefs } from 'vue';
  import useCounter from '../stores/counter';

  const counterStore = useCounter()
	
  // 包裹一层toRefs
  const { counter } = toRefs(counterStore)
</script>

方式二

<script setup>
  import { storeToRefs } from 'pinia';
  import useCounter from '../stores/counter';

  const counterStore = useCounter()

  // 包裹一层storeToRefs
  const { counter } = storeToRefs(counterStore)
</script>

Pinia核心概念State

🍟state基本使用

state 是 store 的核心部分,因为store是用来帮助我们管理状态的

在 Pinia 中,状态被定义为返回初始状态的函数;

前面我们创建了一个counter.js文件用于定义counter的store, 接下来我们创建一个urse.js文件, 定义一个用户信息的store来演示state

在pinia中state和vuex中一样, state是一个函数, 返回一个对象

import { defineStore } from "pinia"

const useUser = defineStore("user", {
  // state定义状态
  state: () => ({
    name: "chenyq",
    age: 18,
    height: 1.88
  })
})

export default useUser

将定义的Store展示到组件中

<template>
  <div class="home">
    <!-- 展示userStore中的状态 -->
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
  </div>
</template>

<script setup>
  import { storeToRefs } from 'pinia';
  // 导入我们自定义的store
  import useUser from "../stores/user"

  // 调用函数创建store
  const userStore = useUser()

  // 将store中的状态解构出来
  const { name, age, height } = storeToRefs(userStore)
</script>

🍟state其他操作

读取和写入 state

默认情况下,您可以通过 store 实例访问状态来直接读取, 刚刚我们就是这样读取状态的

写入状态其实也同理, 通过store实例访问状态直接修改

<template>
  <div class="home">
    <!-- 展示userStore中的状态 -->
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
    <button @click="changeInfo">修改信息</button>
  </div>
</template>

<script setup>
  import { storeToRefs } from 'pinia';
  import useUser from "../stores/user"

  const userStore = useUser()
  const { name, age, height } = storeToRefs(userStore)
  
  function changeInfo() {
    // 使用实例访问状态, 进行修改
    userStore.name = "王老五"
    userStore.age = 20
    userStore.height = 1.89
  }
</script>

重置 State

当我们对某些状态进行了修改之后, 我们可以通过调用 store 上的 $reset() 方法将状态 重置到其初始值

$reset()方法会将所有的状态重置到初始值

<template>
  <div class="home">
    <!-- 展示userStore中的状态 -->
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
    <button @click="changeInfo">修改信息</button>
		<button @click="resetInfo">重置信息</button>
  </div>
</template>

<script setup>
  import { storeToRefs } from 'pinia';
  import useUser from "../stores/user"

  const userStore = useUser()
  const { name, age, height } = storeToRefs(userStore)
  
  function changeInfo() {
    userStore.name = "王老五"
    userStore.age = 20
    userStore.height = 1.89
  }

	function resetInfo() {
    // 重置状态
    userStore.$reset()
  }
</script>

同时修改多个状态

可以调用 $patch 方法 , 它允许您使用部分“state”对象同时应用多个更改;

<template>
  <div class="home">
    <!-- 展示userStore中的状态 -->
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
    <button @click="changeInfo">修改信息</button>
  </div>
</template>

<script setup>
  import { storeToRefs } from 'pinia';
  import useUser from "../stores/user"

  const userStore = useUser()
  const { name, age, height } = storeToRefs(userStore)
  
  function changeInfo() {
    // $patch一次性修改多个状态
    userStore.$patch({
      name: "罗三炮",
      age: 50,
      height: 1.58
    })
  }
</script>

Pinia核心Getters

🍕getters基本使用

Getters相当于Store的计算属性

它们可以用 defineStore() 中的 getters 属性定义;

getters中可以定义接受一个state作为参数的函数;

  • 在defineStore中定义getters
import { defineStore } from "pinia"

const useCounter = defineStore("counter", {
  state: () => ({
    counter: 101
  }),
  // 定义getters
  getters: {
    doubleCounter(state) {
      return state.counter * 2
    }
  }
})

export default useCounter
  • 直接通过store对象就可以访问当前store的Getters
<template>
  <!-- 访问当前store的Getters -->
  <h2>{{ counterStore.doubleCounter }}</h2>
</template>

<script setup>
  import useCounter from "../stores/counter"

  const counterStore = useCounter()
</script>

🍕getters其他操作

Getters中访问自己的其他Getters

我们可以通过this来访问到当前store实例的所有其他属性;

this相当于是绑定的store实例

  • 例如在getter中访问自己的doubleCounter
getters: {
  doubleCounter(state) {
    return state.counter * 2
  },
  doubleCounterAddOne() {
    return this.doubleCounter + 1
  }
}

Getters也可以返回一个函数,这样就可以接受参数:

const useCounter = defineStore("counter", {
  state: () => ({
    counter: 101,
    friend: [
      {id: 111, name: "chenyq"},
      {id: 112, name: "王老五"},
      {id: 113, name: "罗三炮"},
    ]
  }),
  getters: {
    // getter可以返回一个函数
    getfriendById() {
      return (id) => {
        return this.friend.find(item => item.id == id)
      }
    }
  }
})
<h2>{{ counterStore.getfriendById(111) }}</h2>
<h2>{{ counterStore.getfriendById(112) }}</h2>

当前Getters访问其他store中的state/getters

// 导入usrUser
import useUser from "./user"

const useCounter = defineStore("counter", {
  state: () => ({
    counter: 101
  }),
  getters: {
    showMessage(state) {
      // 拿到userStore对象, 获取userStore中的信息
      const userStore = useUser()
      
      // 返回自己store的信息拼接上userStore中的信息
      return `${state.counter}${userStore.name}`
    }
  }
})
<h2>{{ counterStore.showMessage }}</h2>

Pinia核心Actions

🥧Actions基本使用

Actions 相当于组件中的 methods

可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑;

和getters一样,在action中可以通过this访问整个store实例的所有操作

const useCounter = defineStore("counter", {
  state: () => ({
    counter: 101
  }),
  actions: {
    increment() {
      this.counter++
    }
  }
})
<h2>{{ counterStore.counter }}</h2>
<button @click="changeState">+1</button>

<script setup>
  import useCounter from "../stores/counter"

  const counterStore = useCounter()

  function changeState() {
    // 通过store实例调用即可
    counterStore.increment()
  }
</script>

🥧Actions异步操作

Actions中是支持异步操作的,并且我们可以编写异步函数,在函数中使用await

例如在Actions发生网络请求

import { defineStore } from 'pinia'

const useHome = defineStore("home", {
  state: () => ({
    // 定义空数组用于接收网络请求数据
    banners: [],
    recommends: []
  }),
  actions: {
    // 支持异步操作
    async fetchHomeMultidata() {
      // 发送网络请求获取数据
      const res = await fetch("http://123.207.32.32:8000/home/multidata")
      const data = await res.json()

      // 将获取的数据添加到state中
      this.banners = data.data.banner.list
      this.recommends = data.data.recommend.list
    }
  }
})

export default useHome

展示网络请求获取到homeStore中的数据

<template>
  <div class="about">
    <ul v-for="item in homeStore.banners" :key="item.acm">
      <li>{{ item.title }}</li>
    </ul>
  </div>
</template>

<script setup>
  import useHome from "../stores/home"

  const homeStore = useHome()

  // 告知发送网络请求
  homeStore.fetchHomeMultidata()
</script>

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

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

相关文章

React -- useState 的使用及注意事项

一、基本使用 useState是 react 提供的一个定义响应式变量的 hook 函数&#xff0c;基本语法如下&#xff1a; const [count, setCount] useState(initialCount)它返回一个状态和一个修改状态的方法&#xff0c;状态需要通过这个方法来进行修改&#xff1b;initialCount 是我…

Vue3+Vite实现动态路由

项目基本目录 1.首先定义初始默认的路由routes(router.js文件),vue文件使用import引入可以按需加载 import {createRouter,createWebHashHistory } from "vue-router";import store from ../store/index.jsconst routes [{path: "/login",component: () …

jsjiami.com V6版本,js解密的方法。

我们在爬内容&#xff0c;抓取页面的时候&#xff0c;总会遇到sojson v5&#xff0c;jsjiami.com的v6加密。 jsjiami v6 &#xff1a; JS加密,JS不可逆加密,JS混淆,JS混淆加密,JS压缩加密 - [JavaScript加密] 我看了下这个js完全有效。废话不多说。直接上代码。 (function (…

vue中深度选择器

scoped的作用 scoped 可以使当前的样式只在自己当前的组件内起作用。为了防止在一个组件内引入了子组件&#xff0c;而子组件没有加scoped。这个时候如果父子组件有相同的类名&#xff0c;就会产生样式的影响。 原理: 加了scoped就相当于给当前组件所有的标签添加一个【data-v-…

微信小程序实现轮播图

实现轮播图之前必须知道以下三点&#xff1a; 一、轮播图外层容器swiper 二、每一个轮播项swiper-item 三、swiper标签存在默认样式 1. width 100% 2. height 默认为 150px 3 .swiper高度无法实现由内容撑开 默认的150px高度的轮播图如下图: 原图是长这个样子的&#xf…

bootstrap-fileinput(二:编辑(修改)界面文件的上传,回显,删除(数据库同时删除)的操作 )

文章目录bootstrap-fileinput(二&#xff1a;编辑(修改)界面文件的上传&#xff0c;回显&#xff0c;删除(数据库同时删除)的操作 )一、编辑界面文件的上传二、编辑界面文件的回显1.文件的实体类&#xff1a;2.想要回显文件&#xff0c;首先要在工程类(你的编辑界面的主类)里面…

ES6面试问题汇总

面试官通过总问题&#xff0c;ES6方法开始提问 1.ES6有哪些新增方法&#xff1f;/你了解哪些ES6方法&#xff1f;&#xff08;总问题&#xff09; 块级作用域、 模板字符串、 解构赋值、 箭头函数、 函数默认参数、 剩余参数&运算符、 set和map、 import和exprot用…

Vue中实现过渡动画

文章目录Vue的transition动画Transition动画的使用Transition组件的原理Transition动画的classVue的animation动画Animation动画的使用同时设置两种动画(了解)过渡的模式mode列表过渡列表过渡的介绍列表过渡的使用Vue的transition动画 Transition动画的使用 在开发中&#xf…

vite配置cdn优化打包体积

文章目录前言一、版本确认二、使用步骤1.rollup-plugin-visualizer打包体积可视化面板2.配置cdn方法第一种方法&#xff1a; vite-plugin-cdn-import第二种方法&#xff1a; rollup-plugin-external-globals总结前言 大家都知道前端性能优化的方法&#xff0c;cdn外部引入的方…

【微信小程序】小程序知识补充篇

&#x1f381;写在前面&#xff1a; 观众老爷们好呀&#xff0c;这里是前端小刘不怕牛牛频道&#xff0c;小程序系列又更新了呀。 还有就是中秋节就快来啦&#xff0c;程序员过中秋&#xff0c;当然是要好好放松一下啦&#xff0c;那么中秋前我们就不能偷懒了&#xff0c;赶紧学…

Controller层接收前端传参的几种方法。@RequestParam、@RequestBody、@PathVariable。及参数校验。

一、RequestParam 主要用于将请求参数区域的数据映射到控制层方法的参数上 // http://localhost:8080/wh/user/edit?Id9452659856325148452&name天天向上// RequestParam源码Target({ElementType.PARAMETER}) // 只能作用于参数上 Retention(RetentionPolicy.RUNTIME) D…

vue watch监听数据解决新旧值一样的问题(newValue, oldValue)

watch是监听 Vue 实例变化的一个表达式或方法。回调函数得到的参数为新值和旧值。 基础用法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge…

异步函数async

什么是同步异步 在最新的ES7&#xff08;ES2017&#xff09;中提出的前端异步特性&#xff1a;async、await。 在了解async和await之前得先明白什么是同步函数&#xff0c;什么是异步函数。 同步函数&#xff1a;当一个函数是同步执行时&#xff0c;那么当该函数被调用时不会…

前端CryptoJS和Java后端数据互相加解密(AES)

目录一、序言二、关于前端CryptoJS1、CryptoJS简单介绍2、加密和填充模式选择3、前端AES加解密示例(1) cryptoutils工具类(2) 测试用例(3) 加解密后输出内容说明三、Java后端AES加解密1、Java中支持的加密模式和填充说明2、工具类CryptoUtils3、测试用例一、序言 最近刚好在做…

nodejs——解决跨域问题

目录 1什么是跨域 2解决 1 jsonp(缺点&#xff1a;不能请求post请求&#xff09; 1 index.html页 2 proxy.js页面 搭建一个服务器&#xff08;写好代码后&#xff0c;在cmd上启动&#xff09; 3效果 2服务端代理 &#xff08;由于后端请求不受浏览器同源策略影响&…

Bootstrap、栅格系统布局

一、Bootstrap Bootstrap是一个基于HTML、CSS和JavaScript语言编写的框架&#xff0c;具有简单、灵活的特性&#xff0c;拥有样式库、组件和插件。 Bootstrap常用来开发响应式布局和移动设备优先的Web项目&#xff0c;能够帮助开发者快速搭建前端页面。Bootstrap官方网站:Boot…

VUE3构建Cesium项目

目录 1.Cesium开发参考资料 2.VUE中使用Cesium 2.1 使用VUE创建项目 1.创建test项目 2.项目中引入Cesium 3.修改App.vue如下 4.将cesium静态文件复制至public下 5.运行效果 1.Cesium开发参考资料 Cesium官方网站&#xff1a;Cesium: The Platform for 3D Geospatial …

前端接收 type: “application/octet-stream“ 格式的数据并下载,解决后端返回不唯一

前端接收 type: “application/octet-stream“ 格式的数据并下载&#xff0c;还有后端既返回octet-stream还返回JSON数据时的处理方法 今天些项目的时候&#xff0c;后端改了一下文件下载的方式&#xff0c;打算用接口返回 type: “application/octet-stream“格式的数据&…

【微信小程序】全局配置

目录 全局配置文件及常用的配置项 全局配置 - window 1. 小程序窗口的组成部分 2. 了解 window 节点常用的配置项 3. 设置导航栏的标题 4. 设置导航栏的背景色 5. 设置导航栏的标题颜色 6. 全局开启下拉刷新功能 7. 设置下拉刷新时窗口的背景色 8. 设置下拉刷新时 lo…

echarts 柱状图滚动

实现效果&#xff1a;柱形图展示水平滚动条&#xff0c;并且鼠标滚动支持让滚动条平移 echarts文档里&#xff0c;图形的滚动条分两种 内置型 &#xff08;效果是&#xff1a; 鼠标在图中点击拖动平移&#xff0c;在图中滚动缩放&#xff09;滚动条型 &#xff08;效果是&…