Vuex 原理淺析筆記

Mumusen發表於2018-07-21

vuex

::運用場景:根據專案規模判斷::

不能直接改變store,改變store唯一途徑就是顯示地提交mutations。這樣使得我們可以方便跟蹤每一個狀態的變化,從而讓我們實現一些工具幫助我們更好的瞭解我們的應用

state

單一狀態書,用一個物件就包含了全部的應用層級狀態

  • mapState 當一個元件需要獲取多個狀態時候,將這些狀態都宣告為計算屬性會有些重複和冗餘
  • 物件展開符號 …mapState({{})
import { mapState } from 'vuex'
dexport default {
	computed: mapState({
		count: state => state.count,
		countAlias: 'count',
		countPlusLocalState (state) {
			return state.count + this.localCount
		}
		// ...mapState({count}) 擴充套件函式符
	})
}
複製程式碼

getters

從store中的state 中派生出一些狀態

  • mapGetters 輔助函式僅僅是將store中的getters對映到區域性計算屬性
  • 對state進行擴充套件,通過getters 進行設定 (相當於 computed,可以認為是store的計算屬性) 公用的一些方法
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.doneTodos
	}
}
複製程式碼
computed:{
	...mapGetters([
		'doneTodosCount'
	])
}
複製程式碼

mutations

  • 更改Vuex的store中的狀態的唯一方法是提交mutation(不能直接呼叫控制程式碼,必須通過觸發)
  • mutations就是vue methods
  • 每個mutation都有一個字串的事件型別(type)和一個回撥函式(handler)
  • 使用常量替代Mutation事件型別
  • mutation必須是同步函式
//mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'

//store.js
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
	state:{...},
	mutations:{
		[SOME_MUTATION](state){
			//mutate state
		}
	}
})
複製程式碼
Mutations(呼叫篇)
import { mapMutations } from 'vuex'
import { SOME_MUTATION } from './mutation-types'

export default {
	methods:{
		test(){
			this.$store.commit(SOME_MUTATION)
		},
		...mapMutations([
			'SOME_MUTATION'
			//對映 this.increment()為this.$store.commit('SOME_MUTATION')
		])
	}
}
複製程式碼

actions

接受使用者傳過來的event

  • 提交的是mutation
  • 可以包含任何非同步操作
  • mapActions 輔助函式將元件的methods對映為store。dispatch呼叫
  • view -> store.dispatch(‘increment’)
  • action -> commit(‘someMutation’)
actions:{
	async actionA({commit}){
		commit('gotData',await getData())
	},
	async actionB({dispatch,commit}){
		await dispatch('actionA') //等待actionA完成
		commit('gotOtherData',await getOtherData())
	}
}
複製程式碼
Action 呼叫
import { mapActions } from 'vuex'
export default {
	methods:{
		test(){
			store.dispatch('actionB')
		}
	},
	...mapActions([
		'actionB'
		//對映 this.increment()
		//this.$store.dispatch('actionB')
	])
}
複製程式碼

modules

  • Vuex 執行我們將store分割到模組(module)。 每個模組擁有自己的state、mutation、action、getters甚至巢狀子模組——從上至下進行類似的分割
  • store建立之後,你可以使用store.registerModule方法註冊模組
const moduleA = {
	state:{...},
	mutations:{...},
	actions:{...},
	getters:{...}
}

const moduleB = {
	state:{...},
	mutation:{...},
	action:{...}
}
複製程式碼
const store = new Vuex.Store({
	modules:{
		a:moduleA,
		b:moduleB
	}
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態
複製程式碼
store.registerModule('myModule',{
	// ...
})
複製程式碼

plugins

  • Vuex的store接受plugins選項,這個選項暴露出每次mutation的鉤子。Vuex外掛就是一個函式,它接受sotre作為唯一引數
  • 在外掛中不允許直接修改狀態——類似於元件,只能通過提交mutation來觸發變化
  • 自定義的狀態快照
//plugins 程式碼演示
const myPlugin = store => {
	//當store初始化後呼叫
	store.subscribe((mutation, state) => {
		//每次 mutation 之後呼叫
		// mutation 的格式為 {type, payload }
	})
}
複製程式碼
const store = new Vuex.Store({
	plugins: [myPlugin]
})
複製程式碼

Vuex 的思維處理表單

  • <input :value:"message" @input="updateMessage">
  • 測試Actions需要增加一個mocking服務層,測試檔案中用mock服務迴應API呼叫。為了便於解決mock依賴,可以用Webpack 和inject-loader打包測試檔案
  • Hot Module Replacement API ,Vuex 支援在開發過程中熱過載 mutation、modules、actions、getters
測試Actions 演示
import { expect } from ‘chai'
const actionsInjector = require('inject!./actions')
// 使用mocks建立模組
const actions = actionsInjector({
	'../api/shop': {
		getProducts (cb) {
			setTimeout(() => {
				cb([ /* mocked response */ ])
			},100)
		}
	}
})
複製程式碼

測試程式碼

describe('actions', () => {
	it('getAllProducts', done => {
		testAction(actions.getAllProducts,[]),{},[
		{type:'REQUEST_PRODUCTS'},
		{type:'RECEIVE_PRODUCTS',payload:{}}
	]},done)
})
複製程式碼

vuex-router-sync

(sync 同步、async非同步) vue 檢視 vuex 資料來源 vue-router 路由 vuex-router-sync 連線vuex\vue-router

檢視層

<div id="app">
    <h1>Hello APP</h1>
    <p>
    	<router-link to="/foo">go to foo</router-link>
      <router-link to="/bar">go to bar</router-link>
    </p>
    <router-view></router-view>
 </div>
複製程式碼

結合Vuex

import {  sync } from 'vuex-router-sync'
import store from './vuex/store'
import router from './router'
sync(store,router)
this.$store.state.route.path //current path (string)
this.$store.state.route.params //current params (object)
this.$store.state.route.query //current query (object)
複製程式碼

相關文章