多组件共享状态,Vuex/Pinia帮你实现状态管理(Vuex篇)

在Vue中,Vue.js 的状态管理是通过 Vuex 这个官方库来实现的。除了 Vuex 这个官方库可以实现外,还有一个叫Pinia的库,Pinia它也是Vue的一个Store库,它允许我们可以跨组件/页面共享状态。下面我们分别来学习它们吧。

什么是状态管理?

对于Vuex和Pinia的学习,我们先不着急,它们都是帮Vue实现状态管理的库,那么我们需要先了解什么是状态管理呢?

我们从一个简单的记数应用开始,所谓的状态管理就是你对数据的管理,一个状态自管理应用包含这几个部分:

  • 状态------驱动应用的数据源;
  • 视图 ------以声明方式将状态映射到视图;
  • 操作 ------响应在视图上的用户输入导致的状态变化。

下面一张图解释这个简单记数应用的数据状态自管理吧。

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

  • 多个视图依赖于同一状态,也就是这个count数据在多个组件内被使用。
  • 来自不同视图的行为需要变更同一状态。

当多个组件使用同一个数据源时,涉及到的父子组件间状态通信就会变得很复杂,很繁琐,更不利于状态的变更,不同的子组件对状态的同步和更新不能一致,状态维护起来很艰难。为了解决这个问题,Vuex和Pinia,由此诞生了

什么是Vuex?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

简单来说就是将整个应用的状态集中起来管理,然后都按一致的规则对状态进行修改。

Vuex的应用也是需要看场景的,如果不打算开发大型单页应用,建议还是不用Vuex的,使用起来可能让代码繁琐冗余,简单的store模式足矣。下面我们将介绍如何使用Vuex。

Vuex 的核心概念包括:

  1. State(状态):

    • State 包含了整个应用的集中式的数据存储。
    • 每个应用将只会有一个唯一的 store 对象。
  2. Getters(获取器):

    • 类似于计算属性(computed properties),但它是 store 的状态派生出来的结果。
    • Getters 接受 state 作为第一个参数,并可以接受其他 getters 作为第二个参数。
  3. Mutations(变异):

    • 唯一更改 Vuex 的 store 中的状态的方法就是提交 mutation。
    • Mutations 必须同步执行,并且可以被更细粒度地记录、测试等。
  4. Actions(动作):

    • Actions 类似于 mutations,不同在于:
      • 而不是直接变更状态,actions 承载着一些异步操作并可以触发 mutations 来变更状态。
      • Actions 可以包含任意异步操作。
  5. Modules(模块):

    • 当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决这个问题,Vuex 允许我们将 store 分割成模块。

如何使用Vuex?

1. 为项目安装Vuex:

go 复制代码
```
npm install vuex --save
```

2.设置Vuex Store:

接下来,我们将创建一个 Vuex store。在 src 目录下创建一个名为 store 的文件夹,并在其中创建一个名为 index.js 的文件。

src/store/index.js:

scss 复制代码
```
import { createStore } from 'vuex'

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    }
  },
  actions: {
    increment({ commit }) {
      commit('increment')
    },
    decrement({ commit }) {
      commit('decrement')
    }
  },
  getters: {
    count: state => state.count
  }
})

export default store;
```

3.在主应用中使用 Vuex

现在我们需要在主应用中使用这个 Vuex store。

src/main.js:

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import store from './store/index'
const app = createApp(App)
// 向全局注入store对象
app.use(store)
app.mount('#app')

创建 Vue 组件

接下来,我们创建一个 Vue 组件来显示计数器的值,并提供按钮来增加或减少计数值。

src/App.vue:

xml 复制代码
<script setup>
import { ref,computed } from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const count = computed(() => store.getters.count)

const increment = () => store.commit('increment')   // 唤醒一个 mutation 处理函数
const decrement = () => store.commit('decrement')

// const increment = () => store.dispatch('increment')   // 唤醒一个 action 处理函数
// const decrement = () => store.dispatch('decrement')
</script>

这里的import { useStore } from 'vuex';和我们在组件内引入路由对象一样,也是使用useRouter来获取全局路由。

  • 通过查看Vuex的官方文档了解到,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)

要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:

arduino 复制代码
store.commit('increment')  
// commit提交到mutations,提交的字符串type对应的是mutations内的处理函数

上面已经聊到 唯一更改 Vuex 的 store 中的状态的方法就是提交 mutation了,且他还有一个特点就是 Mutations 必须同步执行。

而对于Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

Actions的工作流程:

你可能会问这不是多此一举吗?既然都是在触发mutation ,那为什么不直接调用commit去触发mutations呢?

这就要谈到它的特殊部分了,在Actions内可以存在任何异步操作,在mutations内的代码只能同步执行, mutations内只是有这么一个只能同步执行的准则,大家都应该遵守的规则。

个人观点:

至于为什么,个人认为应该是mutations作为唯一准许修改数据状态的类似于事件的一个东西,他对数据状态不能模棱两可,当我们执行异步操作的时候,需要获取数据状态,然后在其之前执行的同步代码修改了数据,而异步还未执行,若异步用到同步代码修改的那个数据时,已经不是原来的数据了,而是同步代码修改后的数据,这样就乱套了。

结尾

下面用Vuex官网的例子,看看在actions内如何实现异步的供大家观赏:

csharp 复制代码
// 假设 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())  // 执行mutations内部的gotData方法
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())   // 执行mutations内部的gotOtherData方法
  }
}

好了,大概的Vuex的简单操作就是如此了,想要更加深入了解Vuex的jy可以去官网学习Vuex进阶了。链接丢这里 --->Vuex进阶 (vuejs.org)

相关推荐
涵信2 分钟前
第十一节:性能优化高频题-响应式数据深度监听问题
javascript·vue.js·性能优化
拉不动的猪1 小时前
前端常见数组分析
前端·javascript·面试
小吕学编程1 小时前
ES练习册
java·前端·elasticsearch
Asthenia04121 小时前
Netty编解码器详解与实战
前端
袁煦丞1 小时前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
Mr.app2 小时前
vue mixin混入与hook
vue.js
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code3 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员3 小时前
layui时间范围
前端·javascript·layui
NoneCoder3 小时前
HTML响应式网页设计与跨平台适配
前端·html