Vuex状态管理模式

2021-06-16  本文已影响0人  gitJason

Vuex是什么?

Vuex是一个专为Vue.js应用程序开发的状态管理模式
Vuex是全局的状态管理

Vuex用来做什么?

Vuex用于组件之间的传值,多个组件共享数据
Vuex的数据是响应式的,当我们在A组件更新了某个状态,来到B组件,B组件会动态更新

State

State用来存储状态

在组件中获取Vuex状态

由于Vuex的状态存储是响应式的,从store实例中读取状态最简单的方法就是在计算属性中返回某个状态:

computed: {
  count: () => store.state.count
  // or 将状态从根组件“注入”到每一个子组件中 Vue.use(Vuex)
  count: () => this.$store.state.count
},

mapState 获取方式

import { mapState } form 'vuex'

computed: {
    ...mapState({
        // 1. 基础用法 store/index.js
        isLogin: (state) => state.isLogin
        // 2. 使用模块 store/modules/user.js
        isLogin: (state) => state.user.isLogin
    }),
},

Getters

Getters类似计算属性,只有当它的依赖发生改时才会重新求值

Getter 接受 state 作为其第一个参数:

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)
    }
  }
})

在组件中使用

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

mapGetters 获取方式

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
    // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
    // 使用Modules store/user.js
    ...mapGetters('user',[
      'increment',
      'incrementBy',
      // ...
    ])
  }
}

Mutations

更改store中状态的唯一方法是mutations

mutations第一个参数是state

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

调用方法

store.commit('increment')

你可以向store.commit传入额外的参数

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10)

记住 Mutation 必须是同步函数

在组件中提交 Mutation

computed: {
  doneTodosCount () {
    return this.$store.commit('increment')
  }
}

mapMutations 方式提交

import { mapMutations  } from 'vuex'

export default {
  // ...
  methods: {
    // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapMutations([
      'increment',
      'incrementBy',
      // ...
    ])
    // 使用Modules store/user.js
    ...mapMutations('user',[
      'increment',
      'incrementBy',
      // ...
    ])
  }
}

Action

Action 类似于 mutation,不同在于:

注册一个简单的 action:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用context.commit提交一个 mutation,或者通过context.statecontext.getters来获取 state 和 getters。

实践中,我们会经常用到 ES2015 的 参数解构 (opens new window)来简化代码

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

在组件中触发 Action

methods: {
  increment () {
    this.$store.dispatch('increment')
  }
}

mapActions 方式触发

import { mapActions  } from 'vuex'

export default {
  // ...
  methods: {
    // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapActions([
      'increment',
      'incrementBy',
      // ...
    ])
    // 使用Modules store/user.js
    ...mapActions('user',[
      'increment',
      'incrementBy',
      // ...
    ])
  }
}

组合 Action

有时候需要组合多个action,例如有时候需要在actionB中调用actionA

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

利用 async / await ,我们可以如下组合 action:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    // ...
  }
}

Modules

当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
modules 将 store 分割成模块。
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

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

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

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

项目使用案例

@/store/modules/user.js :

export default {
    namespaced: true,
    state: {
        // 存储状态
        isLogin: false
    },
    mutations: {
        // 修改状态
        SET_ISLOGIN(state, val) {
            state.isLogin = val
        }
    },
    actions: {
        // 异步操作
        login({ commit }, query) {
            api.login({
                code: query.code,
                iv: query.iv
            }).then(res => {
                commit('SET_ISLOGIN', true)
            })
        }
    }
}

@/store/index.js :

import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'

// 安装 Vuex
Vue.use(Vuex)

// 创建一个 store
export default new Vuex.Store({
  modules: {
    user,
    // ...
  }
})

@/main.js :

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from '@/store';

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app');
上一篇下一篇

猜你喜欢

热点阅读