多组件共享状态,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)

相关推荐
Myli_ing17 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维35 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
星星会笑滴1 小时前
vue+node+Express+xlsx+emements-plus实现导入excel,并且将数据保存到数据库
vue.js·excel·express
彭世瑜1 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish1 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小五Five2 小时前
TypeScript项目中Axios的封装
开发语言·前端·javascript