什么是Vuex?

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

# State

  • 新建仓库

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        name: 'vuex123'
      },
      mutations: {},
      actions: {},
      modules: {}
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    如果希望通过this.$store访问,需要在Vue实例上挂载store

    //main.js
    new Vue({
      el: '#app',
      store: store,
    })
    
    1
    2
    3
    4
    5
  • 修改state

# mapState

用于将状态映射为组件计算属性,可以和组件的计算属性混合。

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}
1
2
3
4
5
6
7
computed: {
  // 映射 name(){ return this.$store.state.name }
  ...mapState(['name']),
  // 映射sex(){ return this.$store.state.sex }
  //myAge(){ return this.$store.state.age }
  ...mapState({
    sex: state => 'female' ?? state.sex,
    myAge:'age'
  }),
  ...mapGetters(['nameGetter'])
},
1
2
3
4
5
6
7
8
9
10
11

# getter

store 中定义“getter”(可以认为是 store 的计算属性)

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  },
  getUserName: (state) =>
}

1
2
3
4
5
6
7
8

# Mutation

mutations ------ 专门用于存放修改state的方法

//User.vue
输入值:<input @input="increment" type="text" />
    数字:
    <span>{{ $store.state.msg }}</span>

methods: {
  increment(e) {
    this.$store.commit("increment", e.target.value)
    console.log(e)
  }
}
1
2
3
4
5
6
7
8
9
10
11
//Store/index.js
export default new Vuex.Store({
  state: {
    name: 'vuex123',
    msg: ''
  },
  mutations: {
    increment(state, value) {
      // 变更状态
      state.msg = value
    }
  },
  strict: true
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

提交载荷 (opens new window)

注意: mutations中第一个参数永远是state,此外,额外参数最多只能传一个;如果需要传多个参数,请传入一个对象。

另外mutation必须同步执行,如果需要异步执行,使用action

# Action

action接收两个参数*(context: object,payload)*

Mutation 通过 store.commit触发:

store.commit('increment', 10)
1

Action 通过 store.dispatch 方法触发:

store.dispatch('increment') 
1

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
mutations:{
  [SET_STATUS](state, data) {
      state.status = data
    },
}
actions:{
  setStatusAsync({ commit }, value) {
      setTimeout(() => {
        commit(SET_STATUS, value)
      }, 2000)
    },
}
// dispatch actions
$store.dispatch('setStatusAsync', 123)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 以载荷形式分发action

// 载荷形式
store.dispatch('addNewItem', text);

// store.js
  actions: {
    // 载荷形式
    addNewItem(a, text) {
      console.log('a', a);
      console.log('text', text);

      // commit(ADD_NEW_ITEM, text);
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13

打印结果:

image-20210423174626432

# 以对象形式分发action

// 对象形式
    store.dispatch({
      type: 'addNewItem',
      text: text
    });

// store.js
actions: {
    // 对象形式
    addNewItem(o,b) {
      console.log(o,b);
      // commit(ADD_NEW_ITEM, text);
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

打印结果:

image-20210423175408170

打印o:

image-20210423173937509

再看看完整的Store实例:

image-20210423174149491

数据变更流程

# Vuex配合localStorage数据持久化

mutation的方法更新state里面的数据,顺便更新localStorage。

这样在强制刷新页面后,先从localStorage中读取数据,存到Vuex。

localStorage的读取性能没Vuex好,因为localStorage是读磁盘,Vuex是读内存。

const state = {
  userinfo: {
    addressArray: JSON.parse(localStorage.getItem('userinfo'))?.addressArray || [],
    chinaAreaData: JSON.parse(localStorage.getItem('userinfo'))?.chinaAreaData || []
  }
}

const getters = {
  userinfo: (state) => (state.userinfo)
}

const mutations = {
  GET_USERINFO: (state) => (state.userinfo),

  SET_USERINFO: (state, payload) => {
    state.userinfo =
      payload && localStorage.setItem('userinfo', JSON.stringify(payload))
  }
}

const actions = {
  getUserInfo({ commit }) {
    const userinfo = commit('GET_USERINFO')
    return userinfo
  },
  setUserInfo({ commit }, payload) {
    commit('SET_USERINFO', payload)
  }
}

export default {
  state,
  getters,
  mutations,
  actions
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36