vue新一代的状态管理器之pinia

2023-11-13

Pinia 简介

Pinia 是 Vue 新一代的轻量级状态管理库,相当于 Vuex,也是 Vue 核心团队推荐的状态管理库。

同时支持 Vue2 和 Vue3,未来很有可能替代 Vuex,比 Vuex 更容易上手。

特性

Pinia 具有以下几点特性:

  1. 直观,像定义 components 一样地定义 store
  2. 完整的 Typescript 支持
  3. 去除 mutations,只有 state,getters,actions
  4. actions 支持同步和异步
  5. Vue Devtools 支持 Pinia,提供更好的开发体验
  6. 能够构建多个 stores ,并实现自动地代码拆分
  7. 极其轻量(1kb),甚至感觉不到它的存在

图解 pinia

请添加图片描述
对比 vuex

请添加图片描述

Vuex 和 Pinia 的区别

  1. Vuex:
  • Vuex 的 store 需要一个主入口
  • 通过 modules 属性,拆分成不同的模块
  • 自动挂载在 Vue 实例上,通过 this.$store 去调用或者 mapGetters 等方法
  1. Pinia:
  • Pinia 的 store 不需要主入口
  • 直接创建不同的 store 文件即可实现多模块
  • 在使用时,直接通过 js 的模块导入,即可使用,可方便看到从哪个文件导入

安装 Pinia

yarn add pinia
# or with npm
npm install pinia
  1. 引用(main.js)
import { createPinia } from 'pinia'
app.use(createPinia())

定义 Store

创建 store/user.js

import { defineStore } from 'pinia';

const storeUser = defineStore('user', {
  state: () => ({
    count: 0,
    username: '10个肉包子'
  }),
  getters: {},
  actions: {},
});

export default storeUser;

或者

export const useStore = defineStore({
	id: 'user',
    state: () => ({
        count: 0,
        username: '10个肉包子'
  	}),
 	getters: {},
  	actions: {},
})

使用 store

通过 import 导入 js 模块的方式引入,引入后,直接使用变量接收即可。

<script setup>
import storeUser from "../../store/user";
const { counter } = storeUser();
console.log(123, count);
</script>

以上为 pinia 的基础用法。

具体使用方法

State

1. 定义 state

export default defineStore('user', {
    state: () => ({
    	count: 0,
        username: '10个肉包子'
  	}),
});

2. 使用 state

  • 方法 1. 直接获取

    以 javascript 中的模块导出的方式导出 store 数据,state 中的数据均可通过变量.state 数据名获取

<script setup>
import storeUser from "../../store/user";
const { counter } = storeUser();
console.log(123, count);
</script>
  • 方法 2. 解构获取

    store 是一个 reactive 响应式对象,直接解构会使其失去响应式,类似 setup 中的 props,为了既可解构又可保持其响应式,可使用 storeToRefs,它将为每个 reactive 属性创建 refs

<script setup>
import { storeToRefs } from "pinia";
import storeUser from "../../store/user";
const { count } = storeToRefs(storeUser());
console.log(123, count);
</script>
<template>
    <div>
        {{ count }}
    </div>
</template>

3. 修改 state

  • 直接修改 state:
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
store.count++
console.log(123, store);
</script>
  • $patch 已对象修改
<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
store.$patch({
  count: 3,
});
</script>

缺点: 如果只需修改 state 数据中的某一项,仍然需要将整个对象传给 store。

或者

<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
store.$patch(state =>{
	state.count = 3
});
</script>

4. 替换 state

<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
store.$state = { count: 666, username: 'Paimon' }
</script>

5. 重置 state

一键回复默认的 state 数据

<style lang="scss">
</style>
<template>
  <div>index-{{store}}</div>
</template>

<script setup>
import storeUser from "../../store/user";
const store = storeUser();

store.$patch({
  count: 3,
});
setTimeout(() => {
  store.$reset();
}, 3000);
console.log(123, store);
</script>

6. 订阅 state

<style lang="scss">
</style>
<template>
  <div>index-{{store}}</div>
</template>

<script setup>
import storeUser from "../../store/user";
const store = storeUser();

store.$patch({
  count: 3,
});
setTimeout(() => {
  store.$reset();
}, 3000);

store.$subscribe((mutations, state) => {
  console.log(1, mutations);
  console.log(2, state);
});
</script>

在 pinia 实例上监听整个 state

<style lang="scss">
</style>
<template>
  <div>index-{{store}}</div>
</template>

<script setup>
import storeUser from "../../store/user";
import { watch } from "vue";
const store = storeUser();
store.$patch({
  count: 3,
});
setTimeout(() => {
  store.$reset();
  setTimeout(() => {
    store.$patch((state) => {
      state.count = 30;
    });
  }, 5000);
}, 3000);

watch(
  store,
  (state) => {
    console.log(11, state);
  },
  { deep: true }
);

console.log(123, store);
</script>

Getters

1. 获取数据,建议使用尖头函数

export const useStore = defineStore('user', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
})
<template>
    <div> {{ doubleCount }} </div>
    <div> {{ counter }} </div>
</template>
<script setup>
import storeUser from "../../store/user";
import { storeToRefs } from 'pinia'
const store = storeUser();
const { doubleCount, counter } = storeToRefs(storeUser());
</script>

2. 访问其他 getters

访问其他的 getter 需要使用 this, 注意:不能使用尖头函数了

export const useStore = defineStore('user', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.counter * 2
    },
    doublePlusOne() {
      return this.doubleCount + 1
    },
  },
})

3. getters 传递参数

export const useStore = defineStore('user', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})
<template>
  <p>User 2: {{ store.getUserById(2) }}</p>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
</script>

注意: getters are not cached anymore 即 getters 不会被缓存,只能函数调用。

4.访问其他的 getter

即想要哪个 getters 则调用哪个 getter,因为 pinia 没有总入口,和 vuex 有本质区别。

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

5. 使用 mapState 访问 store 中的数据

import { mapState } from 'pinia'
import storeUser from "../../store/user";

export default {
  computed: {
    ...mapState(storeUser, ['doubleCount'])
    ...mapState(storeUser, {
      myOwnName: 'doubleCounter',
      double: state => state.doubleCount,
    }),
  },
}

Actions

1. 获取方法

export const useStore = defineStore('user', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random())
    },
  },
})

2. 使用方法

  • 同步的方式
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
</script>
<template>
    <button @click="store.increment()">增加</button>
</template>

  • 异步的方式
import { mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
  state: () => ({
    userData: {},
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        console.info(`Welcome back ${this.userData.name}!`)
      } catch (error) {
         console.error(error)
        return error
      }
    },
  },
})

3. 访问其他的 actions

和 getter 一样,直接引入其他的 store 即可

import { useAuthStore } from './auth-store'

export const useSettingsStore = defineStore('settings', {
  state: () => ({
    preferences: null,
    // ...
  }),
  actions: {
    async fetchUserPreferences() {
      const auth = useAuthStore()
      if (auth.isAuthenticated) {
        this.preferences = await fetchPreferences()
      } else {
        throw new Error('User must be authenticated')
      }
    },
  },
})

4. 使用 mapActions 访问 store 中的方法

import { mapActions } from 'pinia'
import storeUser from "../../store/user";

export default {
  methods: {
    ...mapActions(storeUser, ['increment'])
    ...mapActions(storeUser, { myOwnName: 'randomizeCounter' }),
  },
}

5. 订阅 actions

使用 store.$onAction()订阅 actions,传递给它的回调函数在 action 之前执行,after 在 actions resolves 之后执行,onError 在 actions 抛出异常和错误的时候执行。

const unsubscribe = someStore.$onAction(
  ({
    name, // name of the action
    store, // store instance, same as `someStore`
    args, // array of parameters passed to the action
    after, // hook after the action returns or resolves
    onError, // hook if the action throws or rejects
  }) => {
    // a shared variable for this specific action call
    const startTime = Date.now()
    // this will trigger before an action on `store` is executed
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // this will trigger if the action succeeds and after it has fully run.
    // it waits for any returned promised
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // this will trigger if the action throws or returns a promise that rejects
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// manually remove the listener
unsubscribe()

$onAction 一般是在组件的 setup 建立,它会随着组件的 unmounted 而自动取消。如果你不想让它取消订阅,可以将第二个参数设置为 true:

export default {
  setup() {
    const someStore = useSomeStore()

    // this subscription will be kept after the component is unmounted
    someStore.$onAction(callback, true)

    // ...
  },
}

总结

本文对 Pinia 的安装、state、getter、action 做了简单的介绍,

官方将 Pinia 中 mutation 移除了,即用即导入,配合 vue3 setup,使得 store 的使用更加灵活

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue新一代的状态管理器之pinia 的相关文章

随机推荐

  • 用于缺陷检测的高分辨率图像的切片处理——工作总结

    目录 参考 背景 原理 切片 标签映射 代码 结果 切片检测结果映射回原图 LabelImg的使用 安装 运行 标注 总结 参考 1 https blog csdn net zengwubbb article details 1158004
  • JS 利用 Set 对数组中对象进行去重

    JS中怎么对一个数组进行去重 相信很多人对这个问题都已经很熟悉了 最简便的方法就是使用 Set let arr 1 2 3 3 4 5 5 console log new Set arr 1 2 3 4 5 那么如何对数组中的对象进行去重呢
  • 刷脸创新技术赋予传统零售智慧发展能力

    其中技术进步起到颠覆性的作用 传统零售商积极拥抱科技进行数字化转型升级 大数据人工智能 人脸识别数据中台等创新技术进入了应用爆发期 与零售产业深度融合 加速零售在经营管理销售 服务等方面优化升级 创新技术赋予了传统零售业智慧发展的能力 在新
  • HTML的段落中怎么样显示出标签要使用的尖括号<>?

    很简单 符号 lt 用 lt 替代 符号 gt 用 gt 替代 示例代码如下 h4 HTML中怎样打出尖括号 h4 p 左尖括号 lt p p 右尖括号 gt p p p 运行效果如下
  • DVWA-xss全等级教程

    low等级 反射型 reflected 在输入框随便输入一串字符 跟踪字符发现其出现在 pre 标签中 于是可以通过自建标签方式进行弹框 这里输入来实现弹框 当然还能输入 img src xx 也可以通过输入 pre
  • Pycharm + anaconda 安装第三方库总是提醒安装失败或者安装包后import失败

    原因 1 pycharm 新建项目后 随项目建立的虚拟环境没有被激活 2 如果用pip安装 有可能是pip没有更形 3 用anaconda安装 有可能是anaconda没有更新 4 第三方库的所在位置不是pycharm项目对应虚拟环境的未知
  • 六、Pytest自动化测试框架 — Pytest预期失败

    文章内容有配套的 学习视频和笔记都放在了文章末尾 Pytest预期失败需要使用 pytest mark xfail 标记 1 pytest mark xfail 标记的作用 期望测试用例是失败的 但是会运行此测试用例 并且也不会影响其他测试
  • hive报错:return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:Got exceptio

    根据网上搜的解决方案 基本都是说连接的mysql编码不对 改alter database hive character set latin1 但是依然报错 根据后半段报错 MetaException message Got exceptio
  • Linux用dd命令制作启动盘

    1 将U盘格式化成 FAT32 格式 按Ctrl R 打开cmd 输入diskpart 输入list disk select disk 1 输入clean 2 在windows 系统上找到Disk Management 选择disk 1 右
  • linux命令批量修改文件名称

    批量修改文件名称 剔除部分相同的内容 for name in ls a do mv name name x86 64 unknown linux gnu a done 解释说明 ls a 是改目录下所有的 a文件 mv 源文件名 替换文件名
  • Unity学习记录——粒子系统与流动效果

    Unity学习记录 粒子系统与流动效果 前言 本文是中山大学软件工程学院2020级3d游戏编程与设计的最终作业 编程题 粒子光环 1 概述 粒子系统在unity官网与老师课件中的概念定义如下 粒子系统 Unity 手册 一个粒子系统可以模拟
  • Python语言程序设计 最新测验题目汇总 嵩天老师

    测验1 Python基本语法元素 Hello World的条件输出 获得用户输入的一个整数 参考该整数值 打印输出 Hello World 要求 如果输入值是0 直接输出 Hello World 如果输入值大于0 以两个字符一行方式输出 H
  • 草根程序员转型做项目管理走过的点点滴滴之"经验总结"

    本篇总结主要以驻场团队的过往经验为基础开展 与其是较经验总结 称呼为过往会议更贴切 团队内部一次交流记录 随后会继续补充完善 1 沟通交流 a 交流的平等基因 不可怯场 把握一个平等的状态投入到沟通交流中去 b 交流的整段性 不要打断客户的
  • 2021年信息安全保研经历分享

    一 写在前面 1 基本信息 学校 排名 某双非学校 信息安全专业 成绩 综合均是rank1 英语 四级560 六级430 获奖 国家奖学金 蓝桥杯省一 几个校奖 项目 一个很水的校级大创 最终去向 东南网安 南京专硕 总的来说 我就是一个无
  • karma配置及使用

    karma配置及使用 一 定义 Karma不是测试框架 也不是断言库 Karma是一个测试工具 一个允许在多个真实浏览器中执行JavaScript代码的工具 为开发人员提供高效的测试环境 代码可能是设计在浏览器端执行的 在node环境下测试
  • qnx的汽车全液晶仪表-基于qnx系统的汽车仪表-车机系统开发

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 声明 本文只用于个人学习交流 若不慎造成侵权 请及时联系我 立即予以改正 锋影 e mail 174176320 qq com QNX系统在
  • 3·15报道:“隔空盗刷”资金骗局曝出

    近些年顾客的网上购物等服务愈来愈多 许多犯罪分子根据 ETC卡禁止使用 快递丢失赔付 等骗术 哄骗顾客登陆诈骗网站对它进行行骗 3 15晚会视频表明 陈女士曾收到一条提醒她ETC卡已禁用短信 需登录网页开展签办 接着 陈女士点链接之后发现
  • vue.js——事件循环机制

    一 事件循环机制介绍 JS是单线程的语言 浏览器和Node js定义了各自的Event Loop 事件循环机制 则是用来解决异步问题 将程序分为 主线程 执行栈 与 Event Loop线程 主线程 自上而下依次执行同步任务 Event L
  • 毕业设计 - 基于java web的在线考试系统【源码+论文】

    文章目录 前言 一 项目设计 1 模块设计 2 基本功能 2 1 登录功能 2 2 系统答题 2 3 答题得分 2 4 错题解析 3 实现效果 二 部分源码 项目源码 前言 今天学长向大家分享一个 Java web 项目 可用于毕业设计 课
  • vue新一代的状态管理器之pinia

    Pinia 简介 Pinia 是 Vue 新一代的轻量级状态管理库 相当于 Vuex 也是 Vue 核心团队推荐的状态管理库 同时支持 Vue2 和 Vue3 未来很有可能替代 Vuex 比 Vuex 更容易上手 特性 Pinia 具有以下