Vuex实现数据共享的方法


Posted in Javascript onDecember 20, 2019

在用vue作为前端框架进行开发的时候,对于组件间的传值你一定不会陌生,如果只是简单的父子组件传值,我想你肯定不会选择用Vuex来进行状态管理,但是如果你需要构建一个中大型单页应用,组件间数据交互比较复杂频繁,你很可能会考虑如何更好地在组件外部管理状态,那么Vuex 将会成为自然而然的选择。

Vuex 是什么?

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

用个人的话总结下: Vuex就是为了实现多组件数据共享,从而建立一个叫store的数据管理库,将需要共享的数据存放在里面,在需要的地方可以取出来作为初始数据,也可以在组件内通过dispatch或者提交commit方法来改变该原始数据状态,从而实现的data的共享。

Vuex的核心

1、 State

Vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过this.$store.state来获取我们定义的数据。

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const state = {
 number: 0
}

export default new Vuex.Store({
 state,
});

在页面中通过this.$store.state.number 即可获取到当前的值。

2、Getter

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

Getter 接受 state 作为其第一个参数:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const state = {
 number: 0
}

const getters = {
 getNumber(state) {
  return state.number + 1
 }
}
export default new Vuex.Store({
 state,
 getters,
});

在页面你可以用两种方式取到getters里面的值

1、通过属性访问

Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值 如: this.$store.getters.getNumber

Getter 也可以接受其他 getter 作为第二个参数:

const state = {
 number: 1
}

const getters = {
 getNumber(state) {
  return state.number + 1 // 2
 },
 getDoubNUmber(state, getters) {
  return state.number + getters.getNumber // 3
 }
}

注意: getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。

2、 通过方法访问

你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。

const state = {
 number: 1,
 list: [1, 2, 3, 4, 5]
}

const getters = {
 getNumber(state) {
  return state.number + 1 // 2
 },
 getDoubNumber(state, getters) {
  return state.number + getters.getNumber // 3
 },
 filterNumber:(state)=>(num)=> {
  return state.list.find(item=> item%num === 0)
 } 
}
export default new Vuex.Store({
 state,
 getters,
});

注意, getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果 this.$store.getters.filterNumber(3)

3、Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方, 并且它会接受 state 作为第一个参数 , 提交载荷(payload) 作为额外的参数 ,并且在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且使记录的 mutation 会更易读:

你可以这样写:

const mutations = {
 increment(state, n) {
 state.number += n
 }
}

但你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:

this.$store.commit('increment', 1)

也可以这样写:

const mutations = {
 increment(state, payload) {
 state.number += payload.count
 }
}

然后:

使用 this.$store.commit('increment', {count: 1})  提交,

// 或者另一种方式是直接使用包含 type 属性的对象进行提交:
this.$store.commit({
 type: 'increment',
 count: 1
})

特别说明:在 Vuex 中,mutation 都是同步任务:为了处理异步操作,让我们来看一看 Action。

4、 Action

Action 类似于 mutation,不同在于:

1、Action 提交的是 mutation,而不是直接变更状态。

2、Action 可以包含任意异步操作。

虽然在页面中通过提交commit是可以达到修改store中状态值的目的,但是官方并不建议我们这样做,而是让我们去提交一个action,在action中提交mutation再去修改状态值。

const mutations = {
 increment(state) {
 state.number += 1
 }
}
const actions = {
 addNumber(context){
  context.commit('increment')
 }
}

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters

addNumber( {commit} ){
 commit('increment')
}

以上这种写法等同于:

addNumber(context){
 context.commit('increment')
}

Action 通过 store.dispatch 方法触发:

this.$store.dispatch('addNumber')

同mutation 一样你也可以在action的时候传递参数

const mutations = {
 increment(state, number) {
 state.number += number
 }
}
const actions = {
 addNumber(context, number){
  context.commit('increment', number)
 }
 或者:
 addNumber( {commit}, number){
  commit('increment', number)
 }
}

触发方法: this.$store.dispatch('addNumber', 10)

关于在action 处理异步操作可以看下面这个例子:

const actions = {
 getData({commit}) {
  return new Promise((resolve, reject)=> {
   setTimeout(()=>{
   commit('getList')
   resolve()
   }, 1000)
  })
 }
}

然后再

this.$store.dispatch('getData').then(() => {
 // ...
})

完整 实例:

import Vue from "vue";
import Vuex from "vuex";
import { resolve, reject } from "any-promise";
Vue.use(Vuex);
const state = {
 number: 1,
 list: [1, 2, 3, 4, 5]
}
const getters = {
 getNumber(state) {
  return state.number + 1 // 2
 },
 getDoubNumber(state, getters) {
  return state.number + getters.getNumber // 3
 },
 filterNumber:(state)=>(num)=> {
  return state.list.find(item=> item%num === 0)
 } 
}
const mutations = {
 increment(state, n) {
 state.number += n
 },
 getList(state) {
 state.list = state.list.forEach((item)=> item*2)
 }
}
const actions = {
 addNumber( {commit} , n){
  commit('increment', n)
 },
 getData({commit}) {
  return new Promise((resolve, reject)=> {
   setTimeout(()=>{
   commit('getList')
   resolve()
   }, 1000)
  })
 }
}
export default new Vuex.Store({
 state,
 getters,
 mutations,
 actions
});

关于 Vuex中mapState、mapGetters、mapMutations、mapActions的用法

要用 首先得引入:

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';

这玩意儿其实就是Vuex 内置的辅助函数,方便我们获取store里面的数据和方法

computed: {
 ...mapState([
 'number'
 ])
}
// 使用对象展开运算符将 getter 混入 computed 对象中
computed: {
 ...mapGetters([
  'getNumber',
  'getDoubNumber',
  // ...
 ])
} 
methods: {
 ...mapMutations([
  'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
 ...mapMutations({
  add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
 })
} 
methods: {
 ...mapActions([
  'addNumber', // 将 `this.addNumber()` 映射为 `this.$store.dispatch('addNumber')`
  // `mapActions` 也支持载荷:
  'addNumber' // 将 `this.addNumber(amount)` 映射为 `this.$store.dispatch('addNumber', amount)`
 ]),
 ...mapActions({
  requestData: 'getData' // 将 `this.requestData()` 映射为 `this.$store.dispatch('getData')`
 })
 }

以上是对Vuex实现状态管理的一个整个过程的理解,参考官方文档,然后自己写一遍,比较容易明白其中的道理,后面有时间想写React里面关于Redux实现状态管理的一个过程,对比其中,其实他们思想差不多, 只不过redux实现过程更多点,敬请期待!

Javascript 相关文章推荐
window.open被浏览器拦截后的自定义提示效果代码
Nov 19 Javascript
javascript两段代码,两个小技巧
Feb 04 Javascript
select标记美化--JS式插件、后期加载
Apr 01 Javascript
javascript打印输出json实例
Nov 11 Javascript
JavaScript Math.round() 方法
Dec 18 Javascript
5个最顶级jQuery图表类库插件【jquery插件库】
May 05 Javascript
jQuery ajax应用总结
Jun 02 Javascript
详解Javascript中prototype属性(推荐)
Sep 03 Javascript
详解堆的javascript实现方法
Nov 29 Javascript
微信小程序模板之分页滑动栏
Feb 10 Javascript
详解Angular5 服务端渲染实战
Jan 04 Javascript
angularJs自定义过滤器实现手机号信息隐藏的方法
Oct 08 Javascript
React 实现车牌键盘的示例代码
Dec 20 #Javascript
jquery实现商品sku多属性选择功能(商品详情页)
Dec 20 #jQuery
JavaScript实现简单计算器功能
Dec 19 #Javascript
微信小程序跨页面数据传递事件响应实现过程解析
Dec 19 #Javascript
js通过循环多张图片实现动画效果
Dec 19 #Javascript
JS实现水平移动与垂直移动动画
Dec 19 #Javascript
5分钟快速看懂ES6中的反射与代理
Dec 19 #Javascript
You might like
PHP字符编码问题之GB2312 VS UTF-8解决方法
2011/06/23 PHP
深入php list()函数的详解
2013/06/05 PHP
PHP模块memcached使用指南
2014/12/08 PHP
PHP基于phpqrcode类生成二维码的方法示例详解
2020/08/07 PHP
Prototype使用指南之selector.js说明
2008/10/26 Javascript
javascript设计模式 封装和信息隐藏(上)
2012/07/24 Javascript
JQuery EasyUI 加载两次url的原因分析及解决方案
2014/08/18 Javascript
JavaScript中常见的字符串操作函数及用法汇总
2015/05/04 Javascript
javascript关于继承解析
2016/05/10 Javascript
详解JS几种变量交换方式以及性能分析对比
2016/11/25 Javascript
JavaScript 最佳实践:帮你提升代码质量
2016/12/03 Javascript
HTML页面定时跳转方法解析(2种任选)
2016/12/22 Javascript
详解Angular2中Input和Output用法及示例
2017/05/21 Javascript
微信小程序实现城市列表选择
2018/06/05 Javascript
json字符串对象转换代码实例
2019/09/28 Javascript
JS实现骰子3D旋转效果
2019/10/24 Javascript
如何在面试中手写出javascript节流和防抖函数
2020/10/22 Javascript
Vue获取微博授权URL代码实例
2020/11/04 Javascript
Python深入学习之内存管理
2014/08/31 Python
Python字符串逐字符或逐词反转方法
2015/05/21 Python
Python随机生成数据后插入到PostgreSQL
2016/07/28 Python
Python简单格式化时间的方法【strftime函数】
2016/09/18 Python
Python轻量级ORM框架Peewee访问sqlite数据库的方法详解
2017/07/20 Python
Python中对象的引用与复制代码示例
2017/12/04 Python
对web.py设置favicon.ico的方法详解
2018/12/04 Python
PyQt5图形界面播放音乐的实例
2019/06/17 Python
Django3.0 异步通信初体验(小结)
2019/12/04 Python
python3中numpy函数tile的用法详解
2019/12/04 Python
什么是JNDI的上下文?如何初始化JNDI上下文
2012/03/10 面试题
Ajax请求总共有多少种Callback
2016/07/17 面试题
保险内勤岗位职责
2014/04/05 职场文书
教师作风整顿个人剖析材料
2014/10/10 职场文书
出差报告怎么写
2014/11/06 职场文书
2014年个人教学工作总结
2014/12/09 职场文书
分享几个JavaScript运算符的使用技巧
2021/04/24 Javascript
Linux中sftp常用命令整理
2022/06/28 Servers