Vuex4学习笔记
一、Vuex的狀態(tài)管理
二、Vuex的安裝
我們這里使用的是vuex4.x,安裝的時候需要添加 next 指定版本;
npm install vuex@next三、創(chuàng)建Store
每一個Vuex應(yīng)用的核心就是store(倉庫):
- store本質(zhì)上是一個容器,它包含著你的應(yīng)用中大部分的狀態(tài)(state);
Vuex和單純的全局對象有什么區(qū)別呢?
第一:Vuex的狀態(tài)存儲是響應(yīng)式的
- 當Vue組件從store中讀取狀態(tài)的時候,若store中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會被更新;
第二:你不能直接改變store中的狀態(tài) - 改變store中的狀態(tài)的唯一途徑就顯示提交 (commit) mutation;
- 這樣使得我們可以方便的跟蹤每一個狀態(tài)的變化,從而讓我們能夠通過一些工具幫助我們更好的管理應(yīng)用的狀態(tài);
使用步驟:
-
創(chuàng)建Store對象;
-
在app中通過插件安裝;
計數(shù)器案例:
四、組件中使用store
在組件中使用store,我們按照如下的方式:
- 在模板中使用;
- 在options api中使用,比如computed;
- 在setup中使用;
五、組件獲取狀態(tài)
在前面我們已經(jīng)學習過如何在組件中獲取狀態(tài)了。
當然,如果覺得那種方式有點繁瑣(表達式過長),我們可以使用計算屬性:
但是,如果我們有很多個狀態(tài)都需要獲取話,可以使用mapState的輔助函數(shù):
- mapState的方式一:對象類型;
- mapState的方式二:數(shù)組類型;
- 也可以使用展開運算符和來原有的computed混合在一起;
六、在setup中使用mapState
在setup中如果我們單個獲取裝是非常簡單的:
-
通過useStore拿到store后去獲取某個狀態(tài)即可;
-
但是如果我們需要使用 mapState 的功能呢?
默認情況下,Vuex并沒有提供非常方便的使用mapState的方式,這里我們進行了一個函數(shù)的封裝:
useState.js:
七、getters的基本使用
某些屬性我們可能需要經(jīng)過變化后來使用,這個時候可以使用getters:
getters可以接收第二個參數(shù):
getters的返回函數(shù)
getters中的函數(shù)本身,可以返回一個函數(shù),那么在使用的地方相當于可以調(diào)用這個函數(shù):
mapGetters的輔助函數(shù)
這里我們也可以使用mapGetters的輔助函數(shù)。
在setup中使用:
封裝useGetters.js:
將前面封裝的useState和useGetters進行再次封裝:
八、Mutation基本使用
更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation:
Mutation攜帶數(shù)據(jù)
很多時候我們在提交mutation的時候,會攜帶一些數(shù)據(jù),這個時候我們可以使用參數(shù):
Mutation常量類型
定義常量:mutation-types.js
定義mutation:
提交mutation:
mapMutations輔助函數(shù)
我們也可以借助于輔助函數(shù),幫助我們快速映射到對應(yīng)的方法中:
在setup中使用也是一樣的:
mutation重要原則
一條重要的原則就是要記住 mutation 必須是同步函數(shù)
- 這是因為devtool工具會記錄mutation的日記;
- 每一條mutation被記錄,devtools都需要捕捉到前一狀態(tài)和后一狀態(tài)的快照;
- 但是在mutation中執(zhí)行異步操作,就無法追蹤到數(shù)據(jù)的變化;
- 所以Vuex的重要原則中要求 mutation必須是同步函數(shù);
九、actions的基本使用
Action類似于mutation,不同在于:
- Action提交的是mutation,而不是直接變更狀態(tài);
- Action可以包含任意異步操作;
這里有一個非常重要的參數(shù)context:
-
context是一個和store實例均有相同方法和屬性的context對象;
-
所以我們可以從其中獲取到commit方法來提交一個mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters;
-
但是為什么它不是store對象呢?這個等到講Modules時再具體來說
actions的輔助函數(shù)
action也有對應(yīng)的輔助函數(shù):
- 對象類型的寫法;
- 數(shù)組類型的寫法;
actions的異步操作
Action 通常是異步的,那么如何知道 action 什么時候結(jié)束呢?
- 我們可以通過讓action返回Promise,在Promise的then中來處理完成后的操作;
十、module的基本使用
什么是Module?
- 由于使用單一狀態(tài)樹,應(yīng)用的所有狀態(tài)會集中到一個比較大的對象,當應(yīng)用變得非常復雜時,store 對象就有可能變得相當臃腫;
- 為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module);
- 每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊;
module的命名空間
默認情況下,模塊內(nèi)部的action和mutation仍然是注冊在全局的命名空間中的:
- 這樣使得多個模塊能夠?qū)ν粋€ action 或 mutation 作出響應(yīng);
- Getter 同樣也默認注冊在全局命名空間;
未使用命名空間時:
如果我們希望模塊具有更高的封裝度和復用性,可以添加 namespaced: true 的方式使其成為帶命名空間的模塊:
- 當模塊被注冊后,它的所有 getter、action 及 mutation 都會自動根據(jù)模塊注冊的路徑調(diào)整命名;
加了命名空間后:
module的局部狀態(tài)
對于模塊內(nèi)部的 mutation 和 getter,接收的第一個參數(shù)是模塊的局部狀態(tài)對象:
module修改或派發(fā)根組件
如果我們希望在home的action中修改root中的state,那么有如下的方式:
module的輔助函數(shù)
如果輔助函數(shù)有三種使用方法:
-
方式一:通過完整的模塊空間名稱來查找;
-
方式二:第一個參數(shù)傳入模塊空間名稱,后面寫上要使用的屬性;
-
方式三:通過 createNamespacedHelpers 生成一個模塊的輔助函數(shù);
useMapper.js:
import {computed} from "vue"; import {useStore} from "vuex";export function useMapper(mapper, mapFn) {const store = useStore()const storeStateFns = mapFn(mapper) // {name: function, age: function}const storeState = {} // {name: ref, age: ref}Object.keys(storeStateFns).forEach((fnKey) => {const fn = storeStateFns[fnKey].bind({$store: store})storeState[fnKey] = computed(fn)})console.log(storeStateFns)console.log(storeState)return storeState }useState.js:
import {createNamespacedHelpers, mapState} from "vuex"; import {useMapper} from "./useMapper";export function useState(moduleName, mapper) {let mapperFn = mapStateif (typeof moduleName === 'string' && moduleName.length > 0) {mapperFn = createNamespacedHelpers(moduleName).mapState} else{mapperFn = moduleName}return useMapper(mapper, mapperFn) }useGetters.js:
import {createNamespacedHelpers, mapGetters} from "vuex"; import {useMapper} from "./useMapper";export function useGetters(moduleName, mapper) {let mapperFn = mapGettersif (typeof moduleName === 'string' && moduleName.length > 0) {// 處理這種情況:useGetters('home', ['increment'])mapperFn = createNamespacedHelpers(moduleName).mapGetters} else {mapperFn = moduleName // 處理這種情況:useGetters(['increment'])}return useMapper(mapper, mapperFn) }十一、nexttick
官方解釋:將回調(diào)推遲到下一個 DOM 更新周期之后執(zhí)行。在更改了一些數(shù)據(jù)以等待 DOM 更新后立即使用它。
比如我們有下面的需求:
- 點擊一個按鈕,我們會修改在h2中顯示的message;
- message被修改后,獲取h2的高度;
實現(xiàn)上面的案例我們有三種方式:
-
方式一:在點擊按鈕后立即獲取到h2的高度(錯誤的做法)
-
方式二:在updated生命周期函數(shù)中獲取h2的高度(但是頁面其他數(shù)據(jù)更新,也會執(zhí)行該操作)
-
方式三:使用nexttick函數(shù);
nexttick是如何做到的呢?
總結(jié)
- 上一篇: 父组件访问子组件中的数据(父子组件通信案
- 下一篇: 十九、MySQL常用命令总结