上一篇筆記寫到如何安裝,接下來就來開始使用 Vuex 做資料管理。
之後的紀錄也都是用 CDN 做安裝喔!
開始第一個 Vuex
1 2
| <div id="vm"></div> <script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>
|
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
| const store = new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { } })
const vm = new Vue({ el: '#vm', store, })
|
state
作用及使用方法
state
類似於 Vue 中 data
的作用,就是用來儲存數據的地方,所以這些在多個模組中都會使用到的資料,就放在 state
裡,以便各模組取用。
用法
創建 Vuex 後,將資料放入 state
中。
1 2 3 4 5 6 7 8 9
| const store = new Vuex.Store({ state: { user: { firstName: 'Celeste', lastName: 'KUO', gender: 'female' } } })
|
在 Vue 中註冊 store
,讓 Vue 的所有模組都可以透過 this.$state
調用 store
。
1 2 3 4 5
| const vm = new Vue({ el: 'vm', store, })
|
透過在模組中 computed
中取得 Vuex store
中的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const vm = new Vue({ el: 'vm', store, computed: { vmUser(){ return this.$store.state.user.firstName } }, })
setTimeout(()=>{ store.state.user.firstName = 'Mark' },1000)
|
為什麼是使用 computed
? 因為 computed
的作用可以創建一種依賴關係,所以當 store.state.user.name
發生變化時,依賴於該值的 vmUser
也會發生變化。
getters
作用及使用方法
類似於 Vue 實例中 computed
的功能,透過在 Vuex getters
中先對 state
中某些屬性的值形成依賴,如果這些屬性值發生改變,那麼有依賴關係的 getters
的屬性也會發生變化。
如此一來,就不需要在每個模組中在對欲使用的 state
寫下邏輯操作了,使用 Vuex getters
只需要寫 1 次邏輯操作就可供多個模組使用。
在 Vuex getters
中對 state
某些值形成依賴。
須注意 getters
的每個方法要固定將 state
作為其第一參數。
1 2 3 4 5 6 7 8 9 10 11 12
| const store = new Vuex.Store({ state: { user: { firstName: 'Celeste', lastName: 'KUO', gender: 'female' } }, getters:{ fullName: state => `${state.user.firstName} ${state.user.lastName}` } })
|
透過在模組中 computed
中取得 Vuex getters
中的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const vm = new Vue({ el: "#vm", store, computed: { vmUser(){ return this.$store.state.user.firstName }, vmFullName(){ return this.$store.getters.fullName } }, });
setTimeout(()=>{ store.state.user.firstName = 'Mark' },1000)
|
Vuex getters
的每個方法也可將 getters
作為其第二參數,並可透過 getters
可與其他的 getters
方法的返回值建立依賴。
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
| const store = new Vuex.Store({ state: { todos: [ { id: 1, text: "shopping", done: true }, { id: 2, text: "washing", done: false }, { id: 3, text: "walking", done: false } ] }, getters: { undones: (state) => state.todos.filter((item) => !item.done), undonesLen: (state, getters) => getters.undones.length } });
const vm = new Vue({ el: "#vm", store, computed: { undones() { return this.$store.getters.undones; }, undonesLen() { return this.$store.getters.undonesLen; } } });
setTimeout(() => { store.state.todos = [ ...store.state.todos, { id: 4, text: "swimming", done: false } ]; }, 1000);
|
可以讓 getters
方法返回一個函數,之後即可調用該函數取得返回值(函數柯理化)。
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: [ { id: 1, text: "shopping", done: true }, { id: 2, text: "washing", done: false }, { id: 3, text: "walking", done: false } ] }, getters: { getTodoById: (state) => (id) => state.todos.find(item => item.id === id) } });
const vm = new Vue({ el: "#vm", store, methods: { getTodoById(id){ return this.$store.getters.getTodoById(id) } } });
|
mutations
作用及使用方法
類似於 Vue 實例中 methods
的功能,並且更改 Vuex 的 store
中的值的唯一方法是提交(commit) mutation
。
mutation
中的方法內容必須是同步函數,以便我們透過 Vue devtools 去做觀察 state
的變化。
建立 mutations
中的方法,並且該方法將 state
作為第一參數。
建立的方法名稱為 type,而事件內容稱為 handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const store = new Vuex.Store({ state: { user: { firstName: 'Celeste', lastName: 'KUO', gender: 'female' } }, mutations: { changeUserName(state) { state.user.firstName = 'Vita'; }, } });
|
要觸發 mutations
,就必須透過 store.commit('type')
來調用該 mutations 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const vm = new Vue({ el: "#vm", store, computed: { vmUser() { return this.$store.state.user.firstName; }, vmFullName() { return this.$store.getters.fullName; } }, methods: { changeUserName(){ this.$store.commit('changeUserName') }, } });
|
mutations
可接受其他數值(通常會是物件)做為第二參數(payload
)喔!
透過 store.commit('type', 'payload')
調用該 mutations
時,將引數帶入 payload 的位置。
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
| const store = new Vuex.Store({ state: { user: { firstName: 'Celeste', lastName: 'KUO', gender: 'female' } }, mutations: { changeUserName(state, payload) { state.user.firstName = payload; }, } });
const vm = new Vue({ el: "#vm", store, computed: { vmUser() { return this.$store.state.user.firstName; }, vmFullName() { return this.$store.getters.fullName; } }, methods: { changeUserName(){ this.$store.commit('changeUserName', 'Vita') }, } });
|
在 mutations
中必須特別注意的事項:
actions
作用及使用方法
類似於 Vue 實例中 methods
的功能,但不同於 mutations
。
與 mutations
的差別:
建立一個 actions
方法。
該方法接受 context
作為第一參數, context
具有 store
相同的屬性及方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const store = new Vuex.Store({ state: { todos: [ { id: 1, text: "shopping", done: true }, { id: 2, text: "washing", done: false }, { id: 3, text: "walking", done: false } ] }, mutations: { changeTodos(state, payload){ state.todos = payload }, }, actions: { getNewTodos(context) { fetch('https://jsonplaceholder.typicode.com/todos/5') .then(response => response.json()) .then(json => { console.log(json); }) }, } });
|
之後透過提交(commit
) mutations
去更改 state
的值。
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
| const store = new Vuex.Store({ state: { todos: [ { id: 1, text: "shopping", done: true }, { id: 2, text: "washing", done: false }, { id: 3, text: "walking", done: false } ] }, mutations: { changeTodos(state, payload){ state.todos = [payload] }, }, actions: { getNewTodos(context) { fetch('https://jsonplaceholder.typicode.com/todos/5') .then(response => response.json()) .then(json => { context.commit('changeTodos', json) }) }, } });
|
相信一定有很多人跟我有相同疑問,為什麼一定要透過提交 mutation
去更改 state
的值?
在網路上找到許多回答,其實在 actions
中變更 state
的值是可行的,但是為了好用 Vue devtools 追蹤狀態修改,所以才建議在 actions
中使用提交 mutation
去更改 state
的值。
參考文件:vuex为什么不建议在action中修改state
透過 store.dispatch('方法名')
觸發 actions
中指定的方法。
1 2 3 4 5 6 7 8 9
| const vm = new Vue({ el: "#vm", store, methods: { changeTodos() { this.$store.dispatch('getNewTodos'); } } });
|
actions
的第一參數可以透過 ES6 中的參數解構來獲得需要使用到的屬性或方法,如此一來程式碼也可以變得更簡潔喔!
actions
可接受其他數值做為第二參數(payload
)喔!
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
| const store = new Vuex.Store({ state: { todos: [ { id: 1, text: "shopping", done: true }, { id: 2, text: "washing", done: false }, { id: 3, text: "walking", done: false } ] }, mutations: { changeTodos(state, payload){ state.todos = [payload] }, }, actions: { getNewTodos({ commit }, payload) { fetch(payload) .then(response => response.json()) .then(json => { context.commit('changeTodos', json) }) }, } });
const vm = new Vue({ el: "#vm", store, methods: { changeTodos() { this.$store.dispatch("getNewTodos","https://jsonplaceholder.typicode.com/todos/5"); } } });
|
Demo
See the Pen
DAY28 | 跟 Vue.js 認識的30天 - Vue 套餐之圖書館 Vuex (中) by Celeste6666 (@celeste6666)
on CodePen.
參考資料
开始 → 核心概念