https://jeremysu0131.github.io/Vue-js-Vuex-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-3-%E7%B0%A1%E5%96%AE%E6%87%89%E7%94%A8/
看到https://jeremysu0131.github.io/Vue-js-Vuex-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-8-actions-%E7%9A%84%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5/
我們用一個更加實際的例子來調用異步 API與分發多重 mutations:
在 actions 中使用 async / await
上面这两句的部份看不懂
1. mapState 輔助函數
當一個組件需要獲取多個 state 的時候,如果每次都要宣告為 computed 會很麻煩,為了解決這個問題 Vuex 讓我們可以使用 mapState 輔助函數來幫助我們,將繁瑣的流程簡化。
使用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <template> <div> <div>{{count}}</div> <div>{{countAlias}}</div> <div>{{countPlusLocalState}}</div> </div> </template> <script> import { mapState } from 'vuex'; export default { data() { return { localCount: 2, }; }, computed: mapState({ // 箭頭函數可以使程式碼更簡潔 count: state => state.count, // 直接傳送字串'count',等同於 `state => state.count` countAlias: 'count', // 為了使用 `this` 來取得組件內的狀態,必須要使用下列特殊的格式 countPlusLocalState(state) { return state.count + this.localCount; }, }), }; </script> |
Output:1, 1, 3
更簡單的使用方式:
1 2 3 4 | computed: mapState([ // 將 this.count 映射為 store.state.count 'count' ]) |
2. getters 使用方式
我們也可以傳參數到 getters 來取得返回結果,這是非常便利的方式查詢 store 中的陣列。
1 2 3 4 5 6 7 8 9 10 11 12 13 | const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } }) |
1 2 3 4 5 6 7 | computed: { getTodoById() { return this.$store.getters.getTodoById(2); } } // { "id": 2, "text": "...", "done": false } |
3. mapGetters 輔助函數
mapGetters
輔助函數與前面提到的 mapState
用法相近,可以簡化程式碼。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <template> <div> <div>{{doneTodos}}</div> <div>{{doneTodosCount}}</div> </div> </template> <script> import { mapGetters } from 'vuex'; export default { computed: { mapGetters([ 'doneTodos', 'doneTodosCount', ]), }, }; </script> |
Output: [ { “id”: 1, “text”: “…”, “done”: true } ], 1
如果我們要將 getters 屬性取另外一個名稱,可以用物件的方式:
新名稱: ‘getters 屬性名稱’
1 2 3 4 | computed: mapGetters({ // 映射 `this.doneCount` 為 `store.getters.doneTodosCount` doneCount: 'doneTodosCount' }), |
4. 展開運算符 (Spread Operator)
上述 mapState 和 mapGetters 都有組件或陣列的兩種寫法,這兩種寫法可以混合使用,只要搭配展開運算符...即可!https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Spread_syntax
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | const store = new Vuex.Store({ state: { count: 0, todos: [{ id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state,getters) => { return getters.doneTodos.length }, getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <template> <div> <div>{{count}}</div> <div>{{countAlias}}</div> <div>{{countPlusLocalState}}</div> <div>{{doneTodos}}</div> <div>{{doneTodosAlias}}</div> <div>{{doneTodosCount}}</div> <div>{{getTodoById}}</div> </div> </template> <script> import { mapState, mapGetters } from 'vuex'; export default { data() { return { localCount: 2, }; }, computed: { // 本地 computed getTodoById() { return this.$store.getters.getTodoById(2); }, // 使用展開運算符將 mapState 混合到外部物件中 ...mapState([ 'count', ]), ...mapState({ countAlias: 'count', countPlusLocalState(state) { return state.count + this.localCount; }, }), // 使用展開運算符將 mapGetters 混合到外部物件中 ...mapGetters([ 'doneTodos', 'doneTodosCount', ]), ...mapGetters({ doneTodosAlias: 'doneTodos', }), }, }; </script> |
5. Mutations 遵守 Vue 的響應規則
因為 Vuex 中的 store 的 state 是響應式的,那麼當我們變更 state 時,監控 state 的組件也會自動更新,這也意味著 Vuex 中的 mutations 也需要與使用 Vue 一樣遵守下列的注意事項:
- 最好提前在 store 中初始化好所有所需的屬性。
- 當新增新的屬性到物件時,你應該:
- 使用
Use Vue.set(obj, 'newProp', 123)
- 或是以新物件替換舊物件,例如我們可以利用
物件展開運算符
來寫:
- 使用
1
| state.obj = { ...state.obj, newProp: 123 }
|
6.使用常量提供 mutations 類型 (這個還沒有懂)
在各種 Flux 實現中,使用常量用於 mutations 類型是一種常見的模式,這樣可以使 IDE 中的各式 linter 工具發揮作用,並將所有常量放在一個文件中,讓你的協作者可以快速瀏覽整個應用程序中可能發生的變化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // 我們可以使用 ES2015 風格的計算屬性命名功能來使用一個常量作為函數名 [SOME_MUTATION] (state) { // mutate state } } }) |
用不用常量取決於自己,但在需要多人協作的大型項目中使用會很有幫助。
7. 在組件中提交 mutations
我們可以在組件中使用
this.$store.commit('xxx')
,提交 mutations 或者使用 mapMutations
輔助函數將組件中的 methods 映射為 store.commit
來調用。1 2 3 4 5 6 7 8 9 10 11 12 13 14 | export default { // ... methods: { ...mapMutations([ 'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')` // `mapMutations` 也支援 payloads: 'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')` }) } } |
methods:{
getapi(){
this.getapi() //這樣會執行失敗,因為Error in v-on handler: "RangeError: Maximum call stack size exceeded"
}
}
8. Actions簡化程式碼
在實際情況中,我們常會使用 ES2015 中的 參數解構 來簡化程式碼:
原來
actions: { increment(context) { context.commit("increment"); } }
簡化後
1 2 3 4 5 | actions: { increment ({ commit }) { commit('increment') } } |
相似的简写法还有dispatch, state,例子如下
actions: { // ... actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } }
actions是用在异步执行,以下说明一些例子(配合new Promise)
state:{
count:10,
},
mutations: {
increment(state, n=3){
state.count+=n;
}
},
actions:{
increment(context){
context.commit('increment');
},
asyncIncrement(context){
return new Promise(resolve =>{
setTimeout(() =>{
context.commit('increment');
resolve();
},3000)
})
},
incrementAsync({commit}){
setTimeout(() => {
commit('increment')
}, 1000)
}
}
<template>
<button @click="handleActionIncrement">action +</button>
<button @click="handleAsyncIncrement2">async2 +</button> //console.log结果是10,一点下去就会出现,不会等一秒!
<button @click="handleAsyncIncrement">async +</button> //console.log结果是13
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
...
methods:{
handleActionIncrement(){
this.$store.dispatch('increment') //dispatch是給action的
},
handleAsyncIncrement (){
this.$store.dispatch('asyncIncrement').then(()=>{
console.log(this.$store.state.count)
},
})
},
handleAsyncIncrement2 (){
this.$store.dispatch('incrementAsync').then(()=>{
console.log(this.$store.state.count)
})
}
9. Modules
https://jeremysu0131.github.io/Vue-js-Vuex-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-9-modules-%E7%9A%84%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5/rootState 是啥??
https://vuex.vuejs.org/zh/guide/modules.html
沒有留言:
張貼留言