vuex之store小白上手指南

563 阅读3分钟

什么是vuex

vuex是项目里面的状态管理器,统一管理和维护各个组件的可变化状态,vue的应用核心是store,vue有五个核心概念,state, getters, mutations, actions, modules。

核心概念

每一个 Vuex 应用的核心就是 store,里面又包括:

  • state,数据,用来存放数据源,就是公共状态 调用:this.$store.state.key

  • getters,数据加工,有的时候需要对数据源进行加工,返回需要的数据 调用:this.$store.getters.fun

  • mutations,执行,操作结束之后,actions通过commit更新state数据源 调用:this.$store.commit('mutation方法名')

  • actions,事件,要执行的操作,可以进行同步或者异步事件。一般用来请求数据,并提交mutations 调用:this.$store.dispatch('action方法名')

  • modules,使用单一状态树,致使应用的全部状态集中到一个很大的对象,所以把每个模块的局部状态分装使每一个模块拥有本身的 state、mutation、action、getters、甚至是嵌套子模块;

工作流程

所以,简单的来说,vuex的工作流程就是:

(1)通过dispatch去提交一个actions

(2)actions接收到这个事件之后,在actions中可以执行一些异步/同步操作,根据不同的情况去分发给不同的mutations

(3)actions通过commit去触发mutations

(4)mutations去更新state数据,state更新之后,就会通知vue进行渲染

创建一个 Store

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

let store = new Vuex.Store({
    state: {},
    getters: {},
    mutations: {},
    actions: {}
})

必须在 Vue.use(Vuex) 之后创建 store

用法说明

state用法说明

存储应用状态数据的对象,state的值可以是一个对象,也可以是一个返回对象的函数,类似vue中组件的data

定义state

const store = new Vuex.Store({
	state: {
		userInfo: false
	}
})

调用state

  • 一般调用
this.$store.state.userInfo

问题:

state 的更新并不会更新视图

解决: 使用computed

<template>
  <div class="home">
    <h2>{{title}}</h2>
    <div>{{content}}</div>
  </div>
</template>

<script>
import store from '@/stores'
export default {
  name: 'home',
  computed: {
    title() {
      return store.state.title
    },
    content() {
      return store.state.content
    }
  }
}
</script>
  • 使用辅助函数mapState调用 当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性,让你少按几次键,通常我们把storestate通过mapState函数映射到组件的computed
<template>
  <div class="home">
    <h2>{{title}}</h2>
    <div>{{content}}</div>
  </div>
</template>

<script>
import {mapState} from 'vuex'

export default {
  name: 'home',
  computed: {
	...mapState([
		'title',
		'content'
	])
  }
}
</script>

getters用法说明

定义一个函数的形式来返回派生数据,也就是state只能返回值,如果对值要进行一些转义,那么就用getters

定义getters

const store = new Vuex.Store({
	state: {
		userInfo: false
	},
	getters: {
		userInfo: (state)=>{
			return state.userInfo
		},
		isLogin: (state)=>{
			return state.userInfo!==false
		},
		username: (state)=>{
			let _username = ''
			if(typeof state.userInfo === 'object'){
				_username = state.userInfo.hasOwenProperty('username') ? state.userInfo.username : ''
			}
			return _username
		},
	}
})

调用getters

  • 一般调用
this.$store.getters.isLogin
  • 使用辅助函数mapGetters调用 与mapState函数类似,通常映射到组件的computed

mutations用法说明

更改Vuexstore中的状态的唯一方法是提交mutationVuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型 (type)和 一个回调函数 (handler)

定义mutations

const store = new Vuex.Store({
	state: {
		userInfo: false
	},
	getters: {
		userInfo: (state)=>{
			return state.userInfo
		},
		isLogin: (state)=>{
			return state.userInfo!==false
		},
		username: (state)=>{
			let _username = ''
			if(typeof state.userInfo === 'object'){
				_username = state.userInfo.hasOwenProperty('username') ? state.userInfo.username : ''
			}
			return _username
		},
	},
	mutations: {
		setUserinfo: (stata, data){
			stata.userInfo = data
			localStorage.setItem('userInfo', data)
		}
	}
})

调用mutations

mutation函数必须是同步的

mutation中的函数不要直接调用

  • 使用commit调用

commit方法没有返回值

store.commit('type', payload)
// or
store.commit({
    type1: payload1,
    type2: payload2,
    ...:...
})

-- type要提交的mutation回调函数名称,type为固定的key -- payload载荷:提交的额外数据,任意格式

  • 使用辅助函数mapMutations调用
import { mapMutations } from 'vuex' // 先从vuex里导入 mapMutations
methods:{
     ...mapMutations([  
        'setUseInfo', //将mutation里的方法映射到该组件内
        'setToken'  //等同于this.$store.commit('setToken')  
      ]),
     changeToken(token){
        this.setToken(token) //由于上一步已经将mutation映射到组件内,所以组件可以直接调用setToken  
     }
     changeUser(userInfo){
        this.setUseInfo(userInfo) //同理
     }
}

actions用法说明

action中的函数与mutation中的函数类似,但是它主要用来进行异步任务的处理,然后通过提交mutation来修改state

注意:action 中的函数不要直接修改 state

定义actions

const store = new Vuex.Store({
	state: {
		userInfo: false,
                token: ''
	},
	getters: {
		userInfo: (state)=>{
			return state.userInfo
		},
		isLogin: (state)=>{
			return state.userInfo!==false
		},
		username: (state)=>{
			let _username = ''
			if(typeof state.userInfo === 'object'){
				_username = state.userInfo.hasOwenProperty('username') ? state.userInfo.username : ''
			}
			return _username
		},
	},
	mutations: {
		setUserinfo: (stata, data){
			stata.userInfo = data
			localStorage.setItem('userInfo', data)
		}
	},
        actions: {
            initUserinfo: ({state, getters, commit, dispatch}, fromServer){
                //state, getters, commit, dispatch使用哪个,引入哪个,但是不要在actions里面直接修改state
                //commit对应mutations里面的方法
                //dispatch对应actions里面的方法
                
		if(fromServer){
                    // 自行引入http哦
                    http.get('member/userinfo', {token:state.token}).then(res=>{
                        if(!res.code){
                            commit('setUserinfo', res.data)
                        }
                    })
                }else{
                    let userInfo = localStorage.getItem('userInfo')
                    if(userInfo) commit('setUserinfo', userInfo)
                }
            }
        }
})

调用actions

action 任务需要通过 dispatch 方法来提交(派发),与 commit 类似

  • 直接通过dispatch调用 dispatch 方法有返回值,且一定返回一个 promise 对象
store.dispatch(type, payload)
// or
store.dispatch({
    type1: payload1,
    type2: payload2,
    ...:...
})
  • 使用辅助函数mapActions调用 与 mapMutations 函数类似,把组件的 methods 映射为 store 的 actions 的 dispatch 调用

小结

stategetters返回值,可以直接调用,但是需要页面同步更新需要写在vue的computed方法中

mutations=>commitactions=>dispatch属于方法调用,可以直接调用,如果要直接在vue中使用通过辅助函数写在VUE的methods方法中

使用 store 注入调用

如果每个组件在使用store的时候都import会比较繁琐,这个时候,我们通过vuex提供的store选项把store对象注入到vue的原型上

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

Vue.config.productionTip = false

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

配置注入后,我们就可以在组件实例中使用this.$store来访问store对象了

<template>
  <div class="home">
    <h2>{{title}}</h2>
    <div>{{content}}</div>
  </div>
</template>

<script>
// import store from '@/stores' // 可以去掉了
export default {
  name: 'home',
  computed: {
    title() {
      return this.$store.state.title
    },
    content() {
      return this.$store.state.content
    }
  }
}
</script>

为什么不能在mutations执行异步操作?

Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过action来提交mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。 每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现time-travel了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。