Vuex状态管理模式

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 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

注册一个简单的 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');
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容

  • Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有...
    skycolor阅读 811评论 0 1
  • Vuex 状态管理模式 在使用vue开发过程中,经常会遇到一个状态在多个组件之间使用,这时候就需要用vuex来状态...
    哭泣哭泣帕拉达阅读 387评论 0 0
  • Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有...
    南崽阅读 299评论 1 2
  • state: 最底层的初始数据 getters: 相当于vue的计算属性,对state数据进行处理 、扩展 mu...
    唯轩_443e阅读 904评论 0 0
  • 前言 我们知道Vue组件通讯基本的方式有 子传父,父传子,平行兄弟组件通信,那么在简单的应用当中,Vue Stor...
    Echonessy阅读 379评论 0 1