使用 Vuex 是为了当元件之间都需要共用资料时,使用一个像是公用容器来管理资料,我们把所有要共用的资料都拉进此容器中,让所有元件都能在此容器取得或操作资料。
使用 Vuex 的好处:
Vuex 的基本架构:
关於 Vuex 的知识会比较多,因篇幅所限,以下只会简述 Vuex 最基本的架构,并以我自己作为新手觉得较重要或常常忽略的部分去解说。
因为 Vuex 会透过 Vue 插件,把 store 实体从根元件注入到子元件里。因此,子元件透过 this.$store
就能操作在 Vuex 里的资料。
当你建立一个有 Vuex 的 Vue CLI 专案,在 store/index.js 就会出现以下的结构,并先利用 createStore
来建立一个 store 的实体。并 export 回到 main.js 里使用。
import { createStore } from 'vuex'
export default createStore({
state: {
// 所有在 store 里的资料
},
actions: {
// 负责触发 mutations
// 可处理非同步程序(e.g: 打 API)
},
mutations: {
// 负责改变 state 里的资料
},
getters: {
// 像 computed 一样,运算处理 state 资料
},
modules: {
// 按需求分拆 module
// 每个 module 都有自己的state, actions, mutations, getters, modules
}
})
未使用 Vuex 之前,资料流会像是下图描述,以 props / emit 为例,当 emit 触发事件,就会修改资料,最後画面会再渲染那笔更新的资料。
画面触发事件(View) --> emit (Actions) --> 修改资料,包括修改 props所传递的资料(State) --> 更新画面 (View)
比起以上做法,Vuex 仍然会遵从单一资料流的做法,但执行过程会更严谨,明显不同是:
整篇文章会以一个简单的 todo list 为例子,但不会每个部分都作讲说,只会针对看看 Vuex 里所有函式需要注意的地方。例子如下:
https://codesandbox.io/s/vuex-vuex-todo-list-shi-fan-b6iud
Actions 作为就是触发 mutations,在函式里可使用 context 参数,例如以下我在例子中的写法:
toggleComplete(context, id) {
this.commit("updateComplete", { id });
}
context 物件就是 store 所有的属性和方法,包括 state, getter 等等:
使用 mutations 时,有两点要先注意:
关於第二点,举例说,以下写法并不建议:
this.$store.commit('changeSth', 你想传递的资料)
这写法是在元件里,直接跳过 actions 来触发 mutations。虽然这不会报错,但是不是良好的写法。因为在众多元件里,有时使用 commit,有时使用 dispatch,就会导致资料流不统一,以致程序难以维护。所以一律建议遵从官方做法,保持使用 dispatch
来触发 actions,再由 actions 触发 mutations。并非直接使用 commit
触发 mutations。
另外,有一个 payload 的物件可以使用。如果我们传送参数到 mutations 时是以物件的方式传送,我们可以在 payload 里找到,例如我在 store/actions.js 是以 { id }
这样来触发 mutations,并把此物件传到 mutaions 里:
TodoCard.vue:
methods: {
changeComplete(id) {
this.$store.dispatch('toggleComplete', id)
}
}
store/actions.js
toggleComplete(context, id) {
this.commit("updateComplete", { id });
}
store/mutations.js
updateComplete(state, payload) {
const target = state.todos.find((todo) => todo.id === payload.id);
target.complete = !target.complete;
}
例如,当我按下 Watch movie,把此 todo 事项的 id (即是 2),传到 toggleComplete
actions 和 updateComplete
mutations 里,在 mutation 再用 console.log(payload)
查看 payload 物件:
如果在 actions 里,不用物件包起来也行。但官方建议是使用物件。有些时候我们会传多笔资料而需要用到的物件,因此统一使用物件会比较单纯。
在元件中操作 store 资料时,可使各种 map helpers 来引入 store 的各种属性到元件里使用。例如我在 computed
里:
import { mapGetters } from 'vuex';
computed: {
...mapGetters({ allTodos: 'getTodos' })
}
以上写法即等於:
computed: {
...mapGetters(['getTodos']),
allTodos() {
return this.getTodos;
}
}
mapGetters 本身是一个函式,它会回传在 store 的 getters 里的函式,例如你传入了 'getTodos'
,它就回传在 store 的 getter 里的 getTodos
函式给你:
mapGetters(['getTodos']) // {getTodos: ƒ}
官方文件这里提到,如果你想为 getTodos
这函式设置另一个属性,就需要传入物件:
mapGetters({ allTodos: 'getTodos' }) // {allTodos: ƒ}
最後,使用展开语法 ...
,把 {allTodos: ƒ}
里的属性和值,展开在我们例子中的 computed 里。
除了 mapGetters,还有其他 map helpers 可以使用。使用方法也是大致相同:
import { mapGetters, mapState, mapActions, mapMutations} from 'vuex';
当专案规模较大时,可以把 store 里的 state、getters、mutations、actions 都独立拆成一个个档案,再逐一引入到 store/index.js 这个主档案中。
档案结构:
store
index.js
getters.js
actions.js
mutations.js
state.js
store/index.js:
import { createStore } from 'vuex';
import state from './state';
import actions from './actions';
import mutations from './mutations';
import getters from './getters';
export default createStore({
state,
actions,
mutations,
getters
});
以 index/actions.js 为例,actions.js 就会放我们所有的 actions 函式:
export default {
toggleComplete(context, id) {
this.commit('updateComplete', { id });
},
...
};
另外,在大型专案里,可以按功能需求去拆分 module,再在主档案 store/index.js 里的 moduleds 属性里引入。每个 module 就是另一个 store,里面同样可以有自己的 state、actions、mutations、getters、modules。
例如在示范的 todo list 例子中,我把备注栏讯息拆成一个 module:
store/Note/index.js
export default {
// 当 namespaced 是 true 时,载入这里的资料时,必须写 'Note/...'
namespaced: true,
state: {
note: 'Dummy text'
},
actions: {
createNote(context, note) {
context.commit('setNote', note);
}
},
mutations: {
setNote(state, note) {
state.note = note;
}
},
getters: {
getNote(state) {
return state.note;
}
}
};
回到主档案 store/index.js,在 modules 属性引入 Note module:
export default createStore({
state,
actions,
mutations,
getters,
modules: {
Note
}
});
并在 App.vue 里引入,把 Dummy text
显示出来:
App.vue:
computed: {
...mapGetters({ allTodos: 'getTodos', note: 'Note/getNote' })
},
以上示范中,我需要用 Note/getNote
来引入 Note module 里的 note 资料。因为我在 Note/index.js 里设定了 namespaced: true
。
设定 namespaced 好处是,在命名所有 state、actions 或 mutations 等等的资料或函式名称时,不用担心与主档案 store/index.js 里的已定义的 state、actions 等资料或函式名称相同,以致产生冲突。同时,提高程序码的可读性,让人一眼就看到此东西是存在於公用的 store,还是某个 module 里。
由画面触发事件 --> 触发 actions --> 触发 mutations --> 修改 state --> 更新画面
store/index.js
的 modules 属性里引入这些 module。2021 Vue3 专业职人 - 入门篇
LEARN VUEX IN 15 MINUTES (VUE.JS STATE MANAGEMENT) FOR 2020 // DAD JOKE GENERATOR APP -VUEX TUTORIAL
Vuex 面试题:使用 vuex 的核心概念
<<: Swift 新手-Design pattern 软件开发设计模式
>>: Day8 用python写UI-聊聊功能钮Button
在.net core mvc跟.net core web api专案中预设各自采用的一些配置 有不太...
今天要讲的是for回圈,他跟while有异曲同工之妙 直接来看看下面的code吧~ var JsFr...
看来今天终於是可以把 Grafana 的章节结束掉了,之前提到我觉得目前找到的 dashboard ...
GCE 昨天有说到了执行个体建立,那如果有需求将相同服务性质绑在同一个群组GCP上是否可以做得到,没...
嗨,我是A Fei,今天真的忙翻,以下是今天的题目: (题目来源: Codewars) The ma...