vuex入门

vuex官方文档

在这里先推荐一个在线编辑工具codesandbox.io,不同于codepen这类的在线代码运行工具,它可以创建一个基本的前端项目,所以对于vue、react的用户比较友好:

它是干嘛的?
它用于对复杂应用进行状态管理,官方称其为状态管理模式
这看起来和EventBus有点相似,但是,一般来说eventbus是用来绑定和触发事件的,并不关心数据的采集。

vuex的核心是store对象,它是一个容器,包含了应用中的状态,与之关联的组件可以通过它分享需要共享的数据。它的基本特征(官网说明):

1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

从一个官方的demo来了解一下vuex:

<div id="app">
	<p>{{ count }}</p>
	<p>
		<button @click="increment">+</button>
		<button @click="decrement">-</button>
	</p>
</div>

<script>
	const store = new Vuex.Store({
		state: {
			count: 0
		},
		mutations: {
			increment: state => state.count++,
			decrement: state => state.count--
		}
	})
	new Vue({
		el: '#app',
		computed: {
			count() {
				return store.state.count
			}
		},
		methods: {
			increment() {
				store.commit('increment')
			},
			decrement() {
				store.commit('decrement')
			}
		}
	})
</script>

在上面的demo中,我们要管理的状态变量是count,如果要修改它的值,我们可以显示地提交mutations

vuex有四大特征属性:

  • state: 用来数据共享存储
  • mutations: 用来注册改变数据状态
  • getters: 用来对共享的数据进行过滤操作
  • actions: 异步修改共享数据

它们都有对应的辅助函数

// store.js
const store = new Vuex.Store({
	state,
	mutations,
	actions,
	getters
})

vuex的数据是单向流动的,运作的流程和原理:

  • vue组件通过dispatch来触发vuex的actions
  • vuex的actions触发自身内部的mutations
  • mutations触发内部的数据源state
  • 数据源state反过来渲染vue组件

state

state内包含需要在应用内共享的数据。假如在state内部有很多变量,我们可以用mapState来辅助操作:

import { mapState } from 'vuex'
export default {
	computed: {
		...mapState({
			name: state => state.name,
			age: state => state.age,
			id: state => state.id
		})
	}
}

或者也可以将箭头函数写成数组的形式:

computed: {
	...mapState(['name', 'age', 'id])
}

demo:

<div id="app">
  <div>
    <child></child>
  </div>
</div>
<script>
Vue.use(Vuex)
const mapState = Vuex.mapState;
	const  store = new Vuex.Store({
		state: {
			name: 'Tom',
			age: '18',
			id: '20'
		}
	})
	const child = {
		  template: `<div><p>{{name}} - {{age}} - {{id}}</p></div>`,
		  computed:{
			    ...mapState([
					'name',
					'age',
					'id'
			])
		  }
	}
	new Vue({
		el: '#app',
	    	store: store,
	    	components: {child},
			mounted() {
				console.log(this.$store.state.name);
				console.log(this.$store.state.age);
				console.log(this.$store.state.id);
		}
	})
</script>

关于如何使用mapState的使用和实现可以参考:vue mapState函数原理分析

mutations

mutations负责直接修改存储状态,其内部的方法总是以state作为第一个参数。激活它内部方法时,不能直接调用mutations handler,需要commit触发。在commit的第一个参数当然是对应的mutations handler,第二个参数被称为mutations的载荷(payload),多数情况下它应该是一个对象:

mutations: {
	increment(state, payload) {
		state.count += payload.amount
	}
}
store.commit('increment', {
	amount: 1
})

// 或者我们可以使用对象风格的commit方式,这样commit传入的参数就是一个对象,这样我们能够更加容易地区分mutations事件类型
store.commit({
	type: 'increment',
	amount: 1
})

用常量来替代mutations事件类型

// mutation-type.js
export const MUTATION = 'MUTATION'

// store.js
import Vuex from 'vuex'
import { MUTATION } from './mutation-type'

const store = new Vuex.Store({
	state: { ... },
	mutations: {
		[MUTATION](state) {
			// ...
		}
	}
})

actions

actions提交的是mutations操作,并且它是异步的。它可以访问到上下文对象(context),通过context,可以访问到state(context.state)、getters(context.getters)和commit(context.commit)

// mutations.js
DELETE_TODO: (state, payload) => {
        let index = state.todos.findIndex(todo => todo.id === payload);
        state.todos.splice(index, 1)
}

//actions.js
deleteTodo: (context, payload) => {
        context.commit('DELETE_TODO', payload)
 }
 
 // 触发的动作
 deleteTodo: function(id) {
    this.$store.dispatch("deleteTodo", id);
}

actions也有辅助函数mapActions:

...mapActions({
	add: 'add'
})

比如我们要访问到commit函数:

// store.js
const actions = {
	add(context, number) {
		context.commit('ADD', number)
	}
}

getters

getters类似计算属性,主要用来负责一些计算操作,它的第一个参数也是state。类似于state,getters也可以用一个辅助函数mapGetters,使用方法类似,不展开

从一个vue-todo的demo来入门vuex操作:

See the Pen vue-todo by simon (@simonchen) on CodePen.