vuex使用理解

1,053 阅读4分钟

先不说原理,直接说使用吧,用着用着就 明白了

A: 需求:

在项目中,组件之间是独立的,组件之间要想实现通信,父子之间通信可以用props选项,但是兄弟之间的通信就比较复杂

B: 简单理解:

如果在state中定义一个数据之后,我们可以在项目中的任何一个组件里获取和修改,并且我们的修改可以得到全局的相应变更 比如

let state = {
  userList: [], // 用户列表
}
这个userList里的数据,可以在全局使用

C: vuex种的五个基本属性

1, 我们可以通过this.$store在vue的组件中获取vuex的实例

2, State:vuex中的数据源,可以通过thsi.$store.state获取在vuex中声明的全局变量的值

3, Getter:相当于vue中的computed(计算属性),可以用于监听/计算state中值的变化

4, Mutation: vuex中提交更改数据的方法(只能同步执行)

5, Action:Action 类似于 mutation

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

6, Module: 模块化vuex

1,先开始使用,在项目中新建一个store文件夹,相当于一个仓库,在store文件夹下面新建index.js文件

import Vue from 'vue'
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex)
const store = new Vuex.Store(); // 实例化
export default store

2, 在main.js里面引入store,然后全局注册一下,这样就可以在任何组件使用this.$store了

import store from './store' //引入store
new Vue({
  el: '#app',
  router,
  store, //使用store
  template: '<App/>',
  components: { App }
})

3, 回到store文件夹的index.js文件,我们声明一个state变量,赋值给一个对象,里面定义两个初始的属性,然后在实例化的Vuex.Store里面传入一个空对象,把声明的state放进去

说明: vuex使用单一状态树,state是唯一数据源,所以每个应用仅包含一个store实例,

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
 const state = { //要设置的全局访问的state对象
    showHello: true,
    changeNum: 0
    //要设置的初始属性值
}
 const store = new Vuex.Store({
   state
})
export default store

说明: 做完这个之后,我们就可以在任何组件里面使用

this.$store.showHello和this.$store.changeNum来获取定义的值了

mapState 辅助函数

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性

// 在单独构建的版本中辅助函数为 Vuex.mapState
// 在需要的组件里面引入
import { mapState } from 'vuex'

 computed: {
    ...mapState({
      showHello:state => state
    })
 }

4,vuex官方提供了一个getter(可以认为是store的计算属性),像计算属性一样,getter的返回值会根据它的依赖被缓存起来,只有当它的依赖值发生改变才会被重新计算,把他也扔到state里面

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state={   //要设置的全局访问的state对象
    showHello: true,
    changeNum: 0
 //要设置的初始属性值
}
const getters = {   //实时监听state值的变化(最新状态)
    isShow(state) {  //方法名随意,主要是来承载变化的showHellor的值
       return state.showHello
    },
    getChangedNum() {  //方法名随意,主要是用来承载变化的changeNum的值
       return state.changeNum
    }
}
const store = new Vuex.Store({
   state,
   getters
});
export default store;

5, 现在只有定义的state初始值,但是我们需要改变初始值,接下来就是mutation了

mutation也是一个对象,这个对象里面放可以改变state初始值的方法

具体的就是:给里面的方法传入参数或者额外的其他参数,理由vue的双向数据驱动进行值得改变

把定义好的mutation也扔进Vuex.Store里面

更改vuex的store中的状态的唯一方法就是提交mutation

vuex中的mutation非常类似事件,就是每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state={  //要设置的全局访问的state对象
    showHellor: true,
    changeNum:0
    //要设置的初始属性值
 };
const getters = { //实时监听state值的变化(最新状态)
    isShow(state) { //承载变化的showHellor的值
       return state.showHellor
    },
    getChangedNum(){ //承载变化的changebleNum的值
       return state.changeNum
    }
};
const mutations = {
// 
    show(state) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
        state.showHellor = true;
    },
    hide(state) { //同上
        state.showHellor = false;
    },
    newNum(state, sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum
       state.changeNum += sum;
    }
};

6, 这个时候就可以用

    this.$store.commit('show') 或 
    this.$store.commit('hide')  以及
    this.$store.commit('newNum',6)在别的组件里面进行改变showHello和changeNum的值了
    
    // 提交 mutation 的另一种方式是直接使用包含 type 属性的对象
    store.commit({
      type: 'increment',
      amount: 10
    })
    
    store.commit 传入额外的参数,即 mutation 的 载荷(payload)

Mutation 需遵守 Vue 的响应规则

1,最好提前在你的 store 中初始化好所有所需属性

2,当需要在对象上添加新属性时,你应该 使用

  Vue.set(obj, 'newProp', 123)

3,或者 以新对象替换老对象。例如,利用对象展开运算符我们可以这样写

state.obj = { ...state.obj, newProp: 123 }

mapMutations 辅助函数将组件中的 methods 映射为 store.commit

import { mapMutations } from 'vuex'
  methods: {
    ...mapMutations([      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`      // `mapMutations` 也支持载荷:      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }

7, 但是在vuex中,mutation里的方法都是同步,意思就是,比如这个this.$store.commit('newNum',sum)方法,

两个组件里用执行得到的值,每次都是一样的,显然不是我们需要的

vuex还提供了actions,把action也放入Vuex.Store里面,这个actions也是对象变量,里面的Action方法,可以包含任意异步操作

这里的异步就是用异步发出mutation里面的方法,action里面的自定义函数接受一个context参数和要变化的形参

context和store实例具有相同的属性和方法,可以调用context.commit()提交一个mutation,或者通过context.state和context.getter来偶去state和getter

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state={ //要设置的全局访问的state对象
    showHello: true,
    changeNum:0
    //要设置的初始属性值
   };
const getters = { //实时监听state值的变化(最新状态)
    isShow(state) { //承载变化的showHello的值
       return state.showHello
    },
    getChangedNum(){ //承载变化的changebleNum的值
       return state.changeNum
    }
};
const mutations = {
    show(state) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
        state.showHello = true;
    },
    hide(state) { //同上
        state.showHello = false;
    },
    newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum
       state.changeNum += sum;
    }
};
 const actions = {
    hideHello(context) { //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性
        context.commit('hide');
    },
    showHello(context) { //同上注释
        context.commit('show');
    },
    getNewNum(context, num){ //同上注释,num为要变化的形参
        context.commit('newNum', num)
    }
};
  const store = new Vuex.Store({
   state,
   getters,
   mutations,
   actions
});
export default store;

实践中我们可以用es6参数解构来简化代码


actions: {
  increment ({ commit }) {
    commit('increment')
  },
   getDep({ commit }) {
    const res = 调用方法之类的 // 拿到值
    if (!res) return;
    commit(TYPES.SET_DEP, res);
    return res;
  },
}

action 通过 store.dispatch 方法触发, dispatch分发action

在外部组件进行全局执行actions里面的方法的时候,你只需要执行

this.$store.dispatch('hideHello')

或this.$store.dispatch('showHello')

以及this.$store.dispatch('getNewNum', 6) //6要变化的实参

mapActions 辅助函数

import { mapActions } from 'vuex'

methods: {
    ...mapActions([      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`      // `mapActions` 也支持载荷:      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }

5.使用常量替代 Mutation 事件类型

  • 使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式
  • 同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// mutations.js
// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // mutate state
    },
    // [SOME_MUTATION]和 show一样,只不过上面用的是常量表示的
    show(state) {
       // mutate state
        // state.showHellor = true;
    },