VueX的学习

130 阅读4分钟

Vuex

  • 专门为Vue.js开发的状态管理模式
  • 他采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
  • 状态具有响应式

什么是状态管理

  • 可理解为变量管理

  • 简单的看成把需要多个组件共享的变量全部存储到一个对象里面

  • 然后将这个对象放在顶层的Vue实例中,让其他组件可以使用

自己实现多个组件共享的对象

const shareObj = {name:'moumangtai'}
//用prototype可以给所有的组件添加一个shareObj属性
Vue.prototype.shareObj = shareObj

//调用
this.shareObj.name
//moumangtai
  • 缺点是虽然可以实现共享,但是不能响应式

哪些状态可能需要多个组件共享

  • 登录状态(token,用户的名称,头像,地理信息等等)
  • 商品的收藏,购物车中的物品
  • 等等

单界面的状态管理

  • View:数据的显示

  • State:对于单个组件来说就是data里的数据

  • Actions:view上产生的一些事件或行为

State->View->Actions->State(形成循环)

全局单例模式(大管家)

  • 将共享的状态抽取出来,交给我们的vuex,同意进行管理
  • 每次访问或者修改等操作都要按照规定好的方式进行

Vuex的状态管理

官方不建议组件直接修改State,而是通过mutation来修改State,这样devtools(用于跟踪是谁修改过该状态)才能跟踪到状态的改变和来源,而如果是一些异步操作,那么就需要先经过actions(异步)再到mutation(同步)

核心概念

State

  • 单一状态树 Single Sourse of truth 也叫单一数据源
  1. 信息的分布虽然可以让结构变得清晰,也保证了信息的安全,但当我们需要用到很多不同的信息时,就需要到不同的系统去提取,就会造成效率低下,而且不方便管理,对于维护也是一个巨大的工作。
  2. 而在vuex里state只有一个store,将所有需要管理的信息,全部放在一个store里。方便维护和调试。

Getters

  • 类似于computed

  • 从store中获取一些变化后的数据(带有计算属性)

  • 具有缓存

  • State是默认参数

    getters:{
        powerState(state){
            return state.counter * state.counter;
        },
        more11peo(state){
            return state.people.filter(s => s.age >= 11)
        }
    }
    
  • 可以将getters做为参数再在getters中使用

    getters:{
        more11peo(state){
            return state.people.filter(s => s.age >= 11)
        },
        //将getters作为参数
        more11peoLength(state, getters){
        	return getters.more11peo.length
        }
    }
    
  • 不定参数的使用

    moreAgepeo(state){
        return function(age){
            return state.people.filter(s => s.age >= age) 
        }
    }
    //<h2>{{$store.getters.moreAgepeo(10)}}</h2>
    

Mutations(同步操作)

  • Vuex的store状态的唯一更新方式:提交mutation

  • 对mutation进行更新

    this.$store.commit('')
    
  • 带参更新(传入进来的参数叫做负载(payload))

    //store的mutations
    mutations:{
        increamentCount(state, counter){
            state.counter += counter
        }
    },
    
    //js
    <button @click="addcount(5)">+5</button>
    
    //methods
    addcount(counter){
        //通过commit来提交mutation从而更新store
        this.$store.commit('increamentCount',counter)
    }
    
  • mutations的提交风格

    1. commit方式

      this.$store.commit('increamentCount',counter)
      
      increamentCount(state, counter){
          //该方式获取到的counter是一个number
          state.counter += counter
      }
      
    2. 包含type属性的对象(可以传多个参数)

      this.$store.commit({
      	type:'increamentCount',
      	//es6语法,这时候的couter是一个对象而不单单是一个number
      	//获取的是整个对象
      	counter
      })
      
      increamentCount(state, payload){
          console.log(payload);
          //这时候获取到的是一个对象payload
          state.counter += payload.counter
      },
      
      //log
      //{type: "increamentCount", counter: 5}
      //	type: "increamentCount"
      //	counter: 5
      //	__proto__: Object
      
  • 如果mutations中含有异步操作,那么devtools就无法监听,跟踪不到发生的变化,虽然页面上发生了变化,但是devtools中跟踪到的数据却没有记录下来。

Actions(异步操作)

将含有异步的操作都放在Action中,但是修改数据时必须通过mutation进行提交

整体流程:component->dispatch->Action->commit->mutation

//component
changeInfo(){
    this.$store.dispatch('achangeInfo')
}
//Action
actions:{
    //context 上下文 当前理解为store本身
    achangeInfo(context){
        setTimeout(()=>{
            context.commit('changeInfo')
        },1000)
    }
},
//mutation
changeInfo(state){
    state.info.name = "asdas"
}

Modules

  • 当state中数据过多时,或者你需要对state中的数据进行抽离,就在module中对state划分模块,而每个模块都可以有自己的state,getters,actions,mutations

  • 当你在modules里划分好了模块,vuex会帮你合并到state里,调用时就用$store.state.模块名

  • mutations和getters不关心你是定义在模块中还是定义在state中,都可以直接调用。(保证不重名的情况下)

  • 在模块中可以传递一个rootState的参数来获取原来State中的数据

Vuex的响应式

  • 首先我们必须遵守一些Vuex的一些规则

    • 提前在store中初始化好所需的属性

      一开始定义好的属性会被加入到响应式系统中,而响应式系统会监听属性的变化,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生刷新

    • 当给state中的对象添加或删除新属性时,使用下面的方式

      1. Vue.set(state.info,'键','值')
      2. Vue.delete(state.info, '键')
      

      如果直接state.info['新的键'] = "新的值"那么vue就不会监听该属性的变化,就不会产生响应式

Vuex的组织结构

对index.js进行抽离

import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
Vue.use(Vuex)
const state = {
    counter:100,
    people:[
        {name:'wqd',age:10}
    ],
    info:{
        name:'name',
        age:15,
        height: 180
    }
}
const store = new Vuex.Store({
    state,
    mutations,
    actions,
    getters,
    modules:{
        a:moduleA
    }
})
export default store