Vuex

这两天在做Vue移动端的项目,正好用到了Vuex,记录一下相关知识。


一、安装

  • npm
npm install vuex --save
  • yarn
yarn add vuex

Vuex是Vue.js 的SPA单页组件化应用程序开发的状态管理模式插件。由于Vue SPA应用的模块化,每个组件都有它各自的数据(state)、界面(view)、和方法(actions)。这些数据、界面和方法分布在各个组件中,当项目内容变得越来越多时,每个组件中的状态会变得很难管理:

  • 保持对所有的事件追踪将变得很困难。到底哪个事件是哪个组件派发的,哪个组件该监听哪个事件?
  • 项目逻辑分散在各个组件当中,很容易导致逻辑的混乱,不利于我们项目的维护。
  • 父组件将变得和子组件耦合越来越严重,因为它需要明确的派发和监听子组件的某些事件。
    所以在vue项目中组件间相互传值或者后台获取的数据需要供多个组件使用的情况很多的话,有必要考虑引入vuex来管理这些凌乱的状态。个人认为它就是决解模块之间的数据通信而存在的,和Redux的思想差不多。

二、Vuex的四个核心概念


上图从左到右,从组件出发,在组件的created中提交dispatch,通过action可以和后台数据交互,比如获取初始化的数据源,或者中间数据的过滤等;然后在 action中去派发 Mutation,触发state状态的改变;最后在组件的计算属性中获取state数据渲染在页面上,视图更新。

  • State
    Vuex使用单一状态树,每个应用仅仅包含一个store实例,因为单一的状态树,可以让我们定位到每一个特定的状态片段,便于调试。
    可以在store的index.js文件中定义一些状态。
const state = {
    playing: false,  
    nowsong: '',
    audioProgss: ''
}

那么如何在组件中获得状态呢?

  • 从 store 实例中读取状态,也就是在计算属性中返回某个状态。
    Vuex 通过 store 选项,提供了一种机制将状态从根组件注入到每一个子组件中(需调用 Vue.use(Vuex))。可以在在main.js文件中引入:
import store from './store'
new Vue({
  router,
  store,
    render: h => h(App)
}).$mount('#app')

该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。

    computed : {
        audioActived : function() {
            return  this.$store.state.playing
        },
        nowsong : function () {
            return this.$store.state.nowsong
        },
        audioProgss : function () {
            let progess = this.$store.state.audioProgss
            if (parseInt(progess) >= 100) {
                this.$emit('nextplay')
            }
            return progess
        }
    },
  • mapState辅助函数
    当组件中需要多个状态时,将这些状态声明为计算属性,会使代码变得冗余。这里可以使用mapState辅助函数生成计算属性。
import { mapState } from 'vuex'
    computed : {
        ...mapState({
            showlist : state => state.playlistToggle,
            playlist : state =>  state.playlist,
            nowsong : state => state.nowsong
        })
    },

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState传一个字符串数组。

import { mapState } from 'vuex'
computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])
  • Getters
  • 创建Getters
    有时需要从state中派生出某些状态,这时就可以用到Getters。在store下面建一个getters的文件夹,用来从state中获取数据。Getters接受state作为其第一个参数。
export default const stop = state => {
    if(state.playing === false) {
      return true
    }
}
  • 获取Getters
    Getters会暴露为store.Getters对象,所以可以在组件中很方便的使用它。
import {mapGetters} from 'vuex'
  computed: {
    ...mapGetters([
      'stop'
    ])
  },
  • Mutations
    要改变Vuex中store的状态唯一的方法就是通过触发mutations,每个 mutation都有一个字符串的事件类型(使用常量) 和 一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
mutations:{
    [REFRESH_DATA] (state, data) {
        state.data = data
    }
}

当触发一个类型为REFRESH_DATA的mutations时,会调用此函数。要使状态发生改变,还需要用到commit,即用来说明一个使 mutation 状态发生改变的操作。
为了能用devtools追踪到状态的变化,mutations必须是同步的。

store.commit('REFRESH_DATA')
  • action
  • 创建action
    action 定义为一个类似事件监听器的模式而不是直接调用它们,提交的是mutations,而且可以包含任意异步操作。
increTranStyle (context, style) { 
    return new Promise((resolve,reject) => {
      context.commit('increTranStyle',style)
      if(context.state.tranStyle === style) {
        resolve()
      }
    })
}
  • 分发action
    可以在Vuex组件的created中分发dispatch,去触发这个事件。和mutations的commit不同,action使用的是dispatch,可以在组件的created中分发dispatch。
created() {
      this.$store.dispatch('increTranStyle');
  }

当然也可以使用 mapActions辅助函数,将组件的 methods 映射为store.dispatch调用。

import {mapActions} from 'vuex'
  methods: {
    ...mapActions([
      'getData'
    ])
  },

三、使用举例

项目的目录结构

这里我是把mutations和action以及getters分别放在不同的文件夹中,当然也可以把它们放在一个modules文件里面。

  • 首先在项目的入口文件main.js中引入store:
import store from './store'

并且将store挂载在vue上:

new Vue({
  router,
  store,
    render: h => h(App)
}).$mount('#app')
  • store的index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './action'
import * as getters from './getters'
import ajax from '../ajax'
Vue.use(Vuex)
const state = {
    getBaseMsg: {
      title: '',  
      features: [],
      retreat: '',
    }
}
export default new Vuex.Store({
    state,
    actions,
    getters,
    mutations,
})
  • 在需要用到state的组件中组件中的中的created分发第一个dispatch。
created() {
    this.$store.dispatch('getBaseMsg');
  }

当然也可以通过mapActions辅助函数,上面已经提到过。

  • 在对应的store下面编写getters、mutations、actions。
    • actions
import ajax from '../ajax'
export default {
    getData({ commit, state }) { //进入action
        ajax('GET', 'http://localhost:9090/info').
        then(res => { // action中调用封装后的ajax成功
            commit('GET_DATA', {
                res
            })
        })
    }
}
  • getters
export const getBaseMsg = state => state.getBaseMsg
  • mutations
const GET_DATA = 'GET_DATA'
export default {
      [GET_DATA](state, payload) { // 进入mutation
        state.getBaseMsg = payload.res; //进入mutations修改state成功
      }
}
  • 最后在需要获取state的组件中使用mapGetters获取对应的state,管理数据非常方便。
import { mapGetters } from 'vuex';
export default {
    ...
    computed: {
      ...mapGetters([
        'getBaseMsg'
      ])
    },
    ...      
}

四、总结

  • 整个数据流都是单向的。
  • 组件可以调用action。
  • action用来派发 Mutation。
  • 只有 mutation 可以改变状态。
  • dispatch用来派发一个action,表明有某些事件发生的意向;而commit用来说明一个使mutation状态发生改变的操作,会使实际状态发生改变的同步操作。
  • store 是响应式的,无论state什么时候更新,组件都将同步更新。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 安装 npm npm install vuex --save 在一个模块化的打包系统中,您必须显式地通过Vue.u...
    萧玄辞阅读 2,901评论 0 7
  • vuex 场景重现:一个用户在注册页面注册了手机号码,跳转到登录页面也想拿到这个手机号码,你可以通过vue的组件化...
    sunny519111阅读 7,971评论 4 111
  • Vuex是什么? Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件...
    萧玄辞阅读 3,070评论 0 6
  • Vuex 的学习记录 资料参考网址Vuex中文官网Vuex项目结构示例 -- 购物车Vuex 通俗版教程Nuxt....
    流云012阅读 1,422评论 0 7
  • vuex是什么鬼? 如果你用过redux就能很快的理解vuex是个什么鬼东西了。他是vuejs用来管理状态的插件。...
    麦子_FE阅读 6,819评论 3 37