面试之Vuex

83 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

Vuex

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

Vuex可以保证数据可追踪,同时不同组件之间可以共享数据。

Vuex的核心概念

Vuex 的五个核心概念:

  • state : 单一状态树
  • mutation: 数据管家(同步更改 state 里面的数据)
  • action : 异步请求
  • getter : 计算属性
  • mudule: 模块管理

创建Vuex

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters: {},
  modules: {}
})

引入Vuex

// main.js
import store from '@/store'

new Vue({
  store,
  render: h =>(App)
}).$mouted('#app')

使用

State

state 是唯一的公共数据源,可以将需要共享的数据统一放到store的state进行储存,类似于统一存储的数据data。

state是响应式的, 只要state值变化, 页面上使用的地方会自动更新同步

const store =  new Vuex.Store({
  state: {
    count: 100
  },
})

使用方法

  1. 组件中直接使用 this.$store.state.count或者$store.state.count
    <script>
    computed: {
        getCount() {
            return this.$store.state.count
        }
    }
    </script>
    
    <p>{{getCount}}</p>
    <p>$store.state.count</p>
    
    
  2. 映射
    <script>
    import { mapState } from 'vuex'
    export default{
      computed: {
        // 数组映射
        ...mapState(['count','state里面的变量名'])
        }
    }
    </script>
    

Mutation

mutations类似数据管家, 可以操作state里的数据,同时是唯一能修改state的地方。

mutations函数内, 只能写同步代码(同步函数), 确保调试工具可以追踪变化过程,因为调试工具要立刻产生一次记录, 所以必须是同步的

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

const store =  new Vuex.Store({
    state: {
        count: 100 // 库存
    },
    mutations: {
        addCount (state, payload) { // 负责增加库存的管家
            state.count += payload
	}
    }
})

使用

  1. 直接使用 this.$store.commit('mutations中的方法名',载荷值)
  2. 映射使用
      methods: {
        ...mapMutations(['addCount','mutations中的方法名']),
        add() {
          // 直接使用
          this.$store.commit('addCount',1)
          // 映射后使用
          this.addCount(1)
        }
      }
    }
    

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作
const store  = new Vuex.Store({
    // ...省略state和mutations此处
    actions: {
        asyncAddCount(store, payload){
            setTimeout(() => { // 1秒后, 异步提交给add的mutations
                store.commit('addCount', payload)
            }, 1000)
        },
        asyncSubCount(store, payload) {
            setTimeout(() => { // 1秒后, 异步提交给sub的mutations
                store.commit('subCount', payload)
            }, 1000)
        }
    }
})

使用

  1. 直接使用
    this.$store.dispatch('actions中的函数名', 载荷值)
    this.$store.dispatch('asyncAddCount',10)
    
    // 载荷值可选
    
  2. 映射使用
    import { mapActions } from 'vuex'
    export default {
        methods: {
            // 2. 把actions里方法映射到原地
            ...mapActions(['asyncAddCount','actions里的函数名'])
        }
    }
    

Getter

vuex里的计算属性, 属于全局计算属性, 类似于vue中的computed,主要是进行缓存,对于Store中的数据进行加工处理形成新的数据

const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos (state) {
          return state.todos.filter(todo => todo.done)
        }
      }
})

使用

  1. 直接使用
    this.$store.getters.计算属性名
    this.$store.getters.doneTodos
    
  2. 映射使用
    import { mapGetters } from 'vuex'
    export default {
        computed: {
          ...mapGetters(['doneTodos','getters里的计算属性名'])
        }   
    }
    

Module

  • 为什么分模块?

    集中式管理项目过大, 变量过多, 会导致state臃肿, 难以维护

  • 如何分模块?

    定义模块对象, state变成函数返回对象形式, 每个模块都有state/mutations/actions/getters/modules

  • 根store如何注册?

    modules里 { 模块名: 模块对象 }

// 写法
const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

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

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
// 访问
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

// 注意:在某个模块中actions里,state是局部状态,根节点状态是rootState
const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

总结

  • 全局单例模式管理只有一个模块

  • mutations和actions的区别:

    mutations是异步操作,actions是同步操作。

    如果要修改state值,只能通过mutations,actions只能通过提交actions修改state