Vuex 初体验

237 阅读2分钟

前言

一般的,我们对数据进行管理是以下流程:

数据修改视图,视图上绑定了一些方法。接受到用户的响应后执行 action 控制对应的数据。

但是这种单向数据流在遇到多个组件共享状态时易碎。

那么如何解决呢?

Vuex 实现了将组件的共享状态抽取出来,以一个全局单例模式管理。 实际上, Vuex 就是一个数据仓库,对象存储数据,数据可被组件共享。

State

  • Vuex 对象存储的数据,与 Vue 实例中的 data 遵循相同的规则

在 Vue 组件中获取 Vuex 数据

  • 把 Vuex 的状态映射到当前组件的计算属性
  • 执行代码我们可以看到 Counter 组件新增了一个计算属性,对应了 Vuex 中的 state 状态。
  • 当 state 状态变化了,多个组件中的计算属性监控到了变化,执行设定的操作。即达到共享属性,同步变化。
	// 注入 Vuex
    Vue.use(Vuex)
    
    // 创建一个 Vuex 对象
    const store = new Vuex.Store({
      state:{
        count :0,
        firstName:'chili',
        lastName:'tom'
      }
    })
    
   // 创建一个 Counter 组件 
    const Counter = {
      template:`<div>{{ count }}</div>`,
      computed:{
        count(){
          return this.$store.state.count
        },
       // ...Vuex.mapState(['firstName','lastName'])
      }
    }
    
    const app = new Vue({
      el:'#app',
      store,
      components:{ Counter },
      template:`
          <div class = "app">
            <Counter/>
          </div>
          `
    })

当 state 里的数据变多且都要一一映射,以上写法太麻烦,我们可以借助** mapState 辅助函数**来达到我们希望的效果。

mapState 返回的是一个数组对象,我们可以将最终对象传给 computed 属性

computed:{
      <!--   count(){
          return this.$store.state.count
        },
        firstName(){
          return this.$store.state.firstName
        },
        lastName(){
          return this.$store.state.lastName
        },   -->
       //等同于
       ...Vuex.mapState(['count','firstName','lastName'])
      }

Getter

  • 类似于组件中的计算属性,因此可以认为是 store 的计算属性
  • 响应式依赖自动缓存

在 Vue 组件中获取 Vuex 中的 Getter

  • 与 state 一样,都是获取查看数据,也会把 Vuex 的 Getter 映射到当前组件的计算属性
 const store = new Vuex.Store({
      state:{
        count :0,
        firstName:'chili',
        lastName:'tom'
      },
     getter:{
       fullName(state){
         return state.firstName+' '+state.lastName
       }
     }
    }) 
    
    const counter = {
      template:`
       <div>
         <div>{{ count }}</div>
         <div>{{ firstName }} {{ lastName }}</div>
         <div>{{ fullName }}</div>
       </div>`,
      computed:{
        ...Vuex.mapState(['count',firstName','lastName']),
        fullName(){
            return this.$store.getters.fullName
      	}
        // ...Vuex.mapGetters(['fullName'])
      }
    }

mapGetters 辅助函数可将 store 中的 getter 映射到计算属性

Mutations (同步函数)

  • 由于直接对修改数据是不可控的,因此可以提供某些方法对属性进行修改。
  • 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
  • 映射到组件中的 methods

会接受 state 作为第一个参数

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})
// 提交 mutation
store.commit('increment')

向 store.commit 传入额外的参数

mutations: {
  increment (state, n) {
    state.count += n
  }
}

store.commit('increment', 2)

在组件中提交 Mutation

  • 使用 this.$store.commit('xxx') 提交 mutation,
  • 使用 mapMutations 辅助函数
 Vue.use(Vuex)
    
   const store = new Vuex.Store({
      state:{
        count :0,
      },
     mutations:{
       increment(state){
         state.count++
       }
     }
    }) 
    
    const counter = {
      template:`
       <div>
         <div>{{ count }}</div>
          <button @click="add">+</button>
       </div>`,
      methods:{
       <!--  add(){
          this.$store.commit('increment')
        } -->
      ...mapMutations({
      add: 'increment' 
      // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
      }
    }
    
    const app = new Vue({
      el:'#app',
      store,
      components:{ counter },
      template:`
          <div class = "app">
            <counter/>
          </div>
          `
    })

Actions (异步操作)

  • 类似与 mutation,都是修改状态
  • Action 提交的是 mutation,而不是直接变更状态。
  • 映射到组件中的 methods
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

在组件中分发 Action

  • 使用 this.$store.dispatch('xxx')
  • 使用 mapActions 辅助函数

Modules

  • 把当前模块的 Vuex 对象进行拆分
  • 代码模块化,具有逻辑性
const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

参考文献:Vuex官网