Vuex状态管理

Vue最核心的两个功能:数据驱动和组价化。
组件化开发的优势就是:更快的开发效率和更好的可维护性
状态管理包含以下几部分:

  • state:驱动应用的数据源
  • view:以声明的方式将state映射到视图
  • actions:响应在view上的用户输入导致的状态变化

什么是vuex

  • Vuex是专门为Vue.js设计的状态管理库
  • 它采用集中式的方式存储需要共享的数据
  • 从使用的角度,他就是一个JavaScript库
  • 他的作用是进行状态管理,解决复杂组件通信,数据共享

什么情况下使用Vuex

  • 多个视图依赖于同一状态
  • 来自不同视图的行为需要变更同一状态
  • 注:Vuex不要来用,否则会让应用变得很麻烦

state

Vuex使用单一状态数,用一个对象就包含了全部的应用层级状态。使用 mapState 简化 State 在视图中的使用,mapState 返回计算属性

// 该方法是 vuex 提供的,所以使用前要先导入 
import { mapState } from 'vuex' 
// mapState 返回名称为 count 和 msg 的计算属性 
// 在模板中直接使用 count 和 msg 
computed: { 
	// ...mapState(['count', 'msg']),
	// 如果当前视图中已经有了 count 和 msg,如果使用上述方式的话会有命名冲突,解决的方式: 
	...mapState({ num: count, message: msg })
}

Getter

Getter 就是 store 中的计算属性,使用 mapGetter 简化视图中的使用

import { mapGetter } from 'vuex' 
computed: {
	...mapGetter(['reverseMsg']), // 改名,在模板中使用 reverse 
	...mapGetter({ reverse: 'reverseMsg' }) 
}

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
使用 Mutation 改变状态的好处是,集中的一个位置对状态修改,不管在什么地方修改,都可以追踪到状态的修改。可以实现高级的 time-travel 调试功能

import { mapMutations } from 'vuex' 
methods: { 
	...mapMutations(['increate']), // 传对象解决重名的问题 
	...mapMutations({ increateMut: 'increate' }) 
}

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
import { mapActions } from 'vuex' 
methods: { 
	...mapActions(['increate']), // 传对象解决重名的问题 
	...mapActions({ increateAction: 'increate' }) 
}

Module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
modules/products.js

const state = {
  products: [
    { id: 1, title: 'iPhone 11', price: 8000 },
    { id: 2, title: 'iPhone 12', price: 10000 }
  ]
}
const getters = {}
const mutations = {
  setProducts (state, payload) {
    state.products = payload
  }
}
const actions = {}

export default {
  namespaced: true, // 如果想让模块具有更好的复用性和封装性,可以给模块开启命名空间。这样在视图中使用模块成员的时候看起来也会更加的清晰
  state,
  getters,
  mutations,
  actions
}

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import products from './modules/products'
import cart from './modules/cart'

Vue.use(Vuex)

export default new Vuex.Store({
  // 所有的状态变更必须通过mutations,但这仅仅只是约定
  // 开启严格模式之后如果在组件中直接修改state会抛出错误
  // 不要在生产环境下开启严格模式,严格模式会深度检查状态数,来检查不和规的改变,会影响性能
  strict: process.env.NODE_ENV !== 'production',
  state: {
    count: 0,
    msg: 'Hello Vuex'
  },
  getters: {
    reverseMsg (state) {
      return state.msg.split('').reverse().join('')
    }
  },
  mutations: {
    increate (state, payload) {
      state.count += payload
    }
  },
  actions: {
    increateAsync (context, payload) {
      setTimeout(() => {
        context.commit('increate', payload)
      }, 2000)
    }
  },
  modules: { // 导入模块
    products,
    cart
  }
})

在组件中使用

 computed: {
    ...mapState('cart', ['cartProducts']), // 开启命名空间后,第一个参数是命名空间的名称,第二个参数才是要引入的属性集合
    ...mapGetters('cart', ['totalCount', 'totalPrice'])
  },
  methods: {
    ...mapMutations('cart', ['deleteFromCart'])
  }

本地存储

Vuex插件介绍

  • Vuex的插件就是一个函数
  • 这个函数接收一个store的参数(在这个函数里面注册一个参数,让他在所有的mutation结束之后执行)
    定义插件在store实例之前
    定义插件

然后再store里面注册插件store里面注册插件
插件中的mutation的结构
插件中的mutation結構

模拟实现Vuex

let _Vue = null
class Store {
  constructor (options) {
    const {
      state = {},
      getters = {},
      mutations = {},
      actions = {}
    } = options
    this.state = _Vue.observable(state)
    this.getters = Object.create(null) // 把创建对象的原型设置为null
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get: () => getters[key](state)
      })
    })
    this._mutations = mutations
    this._actions = actions
  }

  commit (type, payload) {
    this._mutations[type](this.state, payload)
  }

  dispatch (type, payload) {
    this._actions[type](this, payload)
  }
}

function install (Vue) {
  _Vue = Vue
  _Vue.mixin({
    beforeCreate () {
      if (this.$options.store) {
        _Vue.prototype.$store = this.$options.store
      }
    }
  })
}

export default {
  Store,
  install
}

知识点:

  • Object.create(null)
    在Vue和Vuex的源码中,作者都使用了Object.create(null)来初始化一个新对象。为什么不用更简洁的{}呢?
    • Object.create()的定义Object.create(proto,[propertiesObject])
    • proto:新创建对象的原型对象
    • propertiesObject:可选。要添加到新对象的可枚举(新添加的属性是其自身的属性,而不是其原型链上的属性)的属性。
  • Object.create(null)和{}的区别
    分别打印Object.create(null)和{}
    打印结果
    从上图可以看到,{} 新创建的对象继承了Object自身的方法,如hasOwnProperty、toString等,在新对象上可以直接使用。Object.create(null) 新创建的对象原型链上没有任何属性,也就是没有继承Object的任何东西,此时如果我们调用toString()会报Uncaught TypeError的错误。第一个参数使用了null。也就是说将null设置成了新创建对象的原型,自然就不会有原型链上的属性
  • Object.create(null)的使用场景
    • 在我们使用for…in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了,当然,我们也可以直接使用Object.keys[]
    • 你需要一个非常干净且高度可定制的对象当作数据字典的时候;
    • 想节省hasOwnProperty带来的一丢丢性能损失并且可以偷懒少些一点代码的时候
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值