Vue-(十六)狀態管理 vuex(2/2)

一個 vuex 的 Store 中有四大元素:

  • State
  • Mutations
  • Getters
  • Actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
state:{
//count:0,
//userName:"Amy",
//list:[]
},
mutations:{
addCount(state){
state.count += 1;
},
},
});

export default store;

存放狀態的 State

state 是 Vuex.Store 中儲存狀態的物件,裡面就可以存放許多自定義的屬性資料

日後會用到的資料,通常都會事先定義好屬性在 Store 中,即使是空字串、空陣列也沒關係,如果沒有事先定義好,之後就必須要用Vue.set的語法才能在 Store 中新增屬性資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
...
const store = new Vuex.Store({
state:{
count:0,
userName:"",
list:[]
},
mutations:{
addCount(state){
state.count += 1;
},
setLoading(state){
//Store 中還沒有 loading 屬性,所以要用 Vue.set 去新增
Vue.set(state,'loading',false);
}
},
});
...
...

變更狀態的 Mutations

要改變 Store 中的屬性,唯一的方法是透過 Mutation,它的實作方法是在 callBack 函式中,把 state 作為參數傳進去,並在其中重新 assign 值給 state 的屬性。而 mutations 中的操作只能是「同步」操作,不能是非同步操作,如果要非同步操作只能在 actions 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
...
const store = new Vuex.Store({
state:{
count:0,
},
mutations:{
addCount(state){
state.count += 1;

//不得使用非同步操作,如:fetch
// fetch(url).then(()=>{
// state.count +=1;
// });
},
},
});
...
...

取得狀態的 Getters

Getter 其實就是 Store 中的 computed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
...
const store = new Vuex.Store({
state:{
todos:[],
},
getters:{
itemsNotDone(state){
return state.todos.filter(item=> !item.done).length;
},
//將 getters 拿進 getter 中用
itemsDone(state,getters){
return state.todos.length - getters.itemsNotDone;
},
//getter 也可以回傳出一個函式
itemWithID(state){
return ((id)=>{
return state.todos.filter(item=>item.id===id);
})
}
},
});
...
...

在組件中要引用 getters 的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//<script>
import {mapStates, mapGetters} from 'vuex';
export default {
computed:{
...mapStates(['todos']),
...mapGetters(['itemNotDone','itemWithID']),
},
methods:{
test(){
this.itemWithID('123');
},
},
};


//</script>

發出指令的 Actions

前面提過,Mutations 裡面的操作只能是同步的,但若要透過「非同步」 的方式改變 State 裡的資料,就必須使用 Actions 來做操作。可是 Action

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
...
...
const store = new Vuex.Store({
state:{
todos:[],
},
mutations:{
setTodos(state,todos){
state.todos = todos;
}
},
actions:{
fetchTodos(context,payload){
fetch(url).
then(rs => rs.json()).
then(todos=>{
context.commit('setTodos',todos);
})
},

//context 是一個包含 store 中一切的東西,
//可是 context 比 store 還多了一些東西,
//所以 context 不等同於 store。
//因為我們只需要用到 context 中的 commit
//所以這裡經常會使用到重新解構的語法:
fetchTodos({commit},payload){
...
.then(todos=>{
commit('setTodos',todos);
})
...
}
}

});
...
...

在組件中要引用 actions 的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//</script>
import { mapActions} from Vuex;
export default {
mounted(){
this.$store.dispatch('fetchTodos',{id:2});
},
//或是將傳入 dispatch 的參數包成一個物件的寫法
mounted(){
this.$store.dispatch({
type:'fetchTodos',//type 是固定的 key
id:2,
});
},
methods:{
...mapActions(['fetchTodos'])
}
};
//</script>

進階補充:
Actions 可以回傳一個 Promise

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
...
...
const store = new Vuex.Store({
state:{
todos:[],
loading:false,
}
mutations:{
setTodos(state,todos){
state.todos = todos;
},
setLoading(state,loading){
state.loading = loading;
},
},
actions:{
fetchUserInfo(){
...
},
fetchTodos({commit,dispatch},payload){
return new Promise(resolve=>{
commit('setLoadeing',true)
fetch(url)
.then(rs => rs.json())
.then(todos=>{
commit('setTodos',todos);
commit('setLoading',false);
//action 中可以放另一個 action
dispatch('fetchUserInfo');
resolve();
})
})
},
},
});
...
...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//</script>
import { mapActions} from Vuex;
export default {
mounted(){
this.$store.dispatch('fetchTodos',{id:2})
.then((=>{
...
...
}))
},
methods:{
...mapActions(['fetchTodos'])
}
};
//</script>

補:因為 fetch() 本身是個 Promise,所以可以簡化寫法

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
...
...
//簡化前
fetchTodos({commit,dispatch},payload){
return new Promise(resolve=>{
commit('setLoadeing',true)
fetch(url)
.then(rs => rs.json())
.then(todos=>{
commit('setTodos',todos);
commit('setLoading',false);
//action 中可以放另一個 action
dispatch('fetchUserInfo');
resolve();
})
})
},

//簡化後
fetchTodos({commit,dispatch},payload){
return fetch(url)
.then(rs => rs.json())
.then(todos=>{
commit('setTodos',todos);
commit('setLoading',false);
//action 中可以放另一個 action
dispatch('fetchUserInfo');
resolve();
})
},
...
...

© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero