文章加密

;

2019年5月22日 星期三

vuex全解說 -- mapState, getters帶參數, mapGetters, 展開運算符...,

這個有很多章,下面的圖片就是從這個的第一章來的
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 中的陣列。















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)
    }
  }
})
component
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














uex
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)
    }
  }
});
component
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 一樣遵守下列的注意事項:
  1. 最好提前在 store 中初始化好所有所需的屬性。
  2. 當新增新的屬性到物件時,你應該:
    • 使用 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')`
    })
  }
}
只是將 `this.increment()` 映射為 `this.$store.commit('increment')`,不能直接把它拿去@click="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

沒有留言:

張貼留言