vuex 源碼解析(四) mutation 詳解

来源:https://www.cnblogs.com/greatdesert/archive/2019/09/12/11424193.html
-Advertisement-
Play Games

mutation是更改Vuex的store中的狀態的唯一方法,mutation類似於事件註冊,每個mutation都可以帶兩個參數,如下: state ;當前命名空間對應的state payload ;傳入的參數,一般是一個對象 創建Vuex.Store()倉庫實例時可以通過mutations創建每 ...


mutation是更改Vuex的store中的狀態的唯一方法,mutation類似於事件註冊,每個mutation都可以帶兩個參數,如下:

  state     ;當前命名空間對應的state

  payload     ;傳入的參數,一般是一個對象

創建Vuex.Store()倉庫實例時可以通過mutations創建每個mutation

我們不能直接調用一個mutation,而是通過 store.commit來調用,commit可以帶兩個參數,如下:

  type     ;對應的mutation名

  payload    ;傳入的參數

commit還有一種寫法,就是傳入一個對象即可,該對象可以帶一個type參數,type指定為mutation的名稱,整個對象會作為參數傳遞給mutation。註意:mutation里包含的是同步操作

例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/vuex.js"></script>
</head>
<body>

    <div id="app">
        <p>{{no}}</p>
        <button @click="test1">測試1</button>
        <button @click="test2">測試2</button>
    </div>
    <script>
        const store = new Vuex.Store({
            state:{no:100},
            mutations:{
                increment(state,payload){state.no+=payload.no;}
            }
        })
        var app = new Vue({
            el:"#app",
            store:store,
            computed:{
                no(){return this.$store.state.no }
            },
            methods:{
                test1(){
                    this.$store.commit('increment',{no:100})            //一般調用mutation的方法
                },
                test2(){
                    this.$store.commit({type:'increment',no:100})       //mutation的另一種寫法
                },
            }
        })  
    </script>

</body>
</html>

 

源碼分析


在創建Vuex.Store()初始化時會執行installModule()安裝根模塊,和mutation相關的如下:

  function installModule (store, rootState, path, module, hot) {      //安裝模塊
    /**/

    module.forEachMutation(function (mutation, key) {                   //遍歷module模塊的mutations對象,如果找到了,則執行這個匿名函數 參數1:每個mutation值 key:對應的鍵名
      var namespacedType = namespace + key;                                 //拼湊namespacedType
      registerMutation(store, namespacedType, mutation, local);             //調用registerMutation註冊mutation
    });
    /**/
  }

 registerMutation用於註冊mutation的,如下:

  function registerMutation (store, type, handler, local) {             //註冊Mutations
    var entry = store._mutations[type] || (store._mutations[type] = []);  //如果store對象的_mutations對應的為空,則初始化為數組
    entry.push(function wrappedMutationHandler (payload) {                //則將一個匿名函數push到entry裡面  
      handler.call(store, local.state, payload);                            //上下文是store,參數1為local.state,參數2為payload
    });
  }

writer by:大沙漠 QQ:22969969

也就是說註冊完後對應的mutation會存儲在store._mutations里,這是一個對象,每個鍵是一個mutation,而值就是對應的mutation,是個數組,例如例子里執行到這裡時對應的_mutation如下:

 

等到我們調用this.$store.commit('increment',{no:100})去觸發一個mutation時首先會觸發Store函數內重定義的commit,它會以當前Store函數對象為上下文繼續執行Store原型上的commit函數,如下:

  Store.prototype.commit = function commit (_type, _payload, _options) {      //對mutation的處理
      var this$1 = this;

    // check object-style commit
    var ref = unifyObjectStyle(_type, _payload, _options);                      //規範一下參數,返回一個對象,例如:{options: undefined,payload: {no: 100},type: "increment"}
      var type = ref.type;                                                      //mutagion類型:比如:increment
      var payload = ref.payload;                                                //傳遞過來的參數
      var options = ref.options;                                                //選項

    var mutation = { type: type, payload: payload };  
    var entry = this._mutations[type];                                          //直接從this._mutations里獲取type類型的mutaion,是個函數數組
    if (!entry) {                                                               //如果該mutaion不存在,則報錯
      {
        console.error(("[vuex] unknown mutation type: " + type));
      }
      return
    } 
    this._withCommit(function () {                                              //在this._withCommit()環境下執行該函數
      entry.forEach(function commitIterator (handler) {                           //遍歷entry,依次執行每個handler函數,參數為payload
        handler(payload);
      });
    });
    this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); });

    if (
      options && options.silent
    ) {
      console.warn(
        "[vuex] mutation type: " + type + ". Silent option has been removed. " +
        'Use the filter functionality in the vue-devtools'
      );
    }
  };

unifyObjectStyle是一個工具函數,它會修正參數,並返回一個對象,如下:

  function unifyObjectStyle (type, payload, options) {        //統一object的類型
    if (isObject(type) && type.type) {                          //如果type是個類型且含有type屬性,比如這樣的格式:this.$store.commit({type:'increment',no:1000})
      options = payload;
      payload = type;
      type = type.type;
    }

    {
      assert(typeof type === 'string', ("expects string as the type, but found " + (typeof type) + "."));
    }

    return { type: type, payload: payload, options: options }   //最後返回該對象
  }

我們在例子里可以用兩種方式來調用mutation也是這個unifyObjectStyle函數的作用

_withCommit是一個工具函數,如下:

Store.prototype._withCommit = function _withCommit(fn) {                //執行fn函數 執行時設置this._committing為true,執行完後設置為false
    var committing = this._committing;                    //保存this._committing到局部變數committing里
    this._committing = true;                        //設置this._committing為true
    fn();                                 //執行fn函數
    this._committing = committing;                      //恢復this._committing
};

它在執行傳入的函數時會設置Store._committing為true,這樣就相當於設置了一個標記,表示當前是通過mutation來修改state的,還記得上一節說的strict嚴格模式嗎,它就是通過這裡的_committing來判斷是否合法的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.模板缺陷 模板的最大特點是擴展難度大,不易擴展。可能會造成邏輯冗餘 Level組件需要對不同的type產生不同的標簽 二.函數式組件 函數式組件沒有模板,只允許提供render函數 複雜的邏輯變得非常簡單 三.JSX應用 使用jsx會讓代碼看起來更加簡潔易於讀取 四.render方法訂製組件 編 ...
  • "在這裡閱讀效果更佳" 還記得當年和同桌在草稿紙上下三子棋的時光嗎 今天我們就用代碼來重溫一下年少(假設你有react基礎,沒有也行,只要你會三大框架的任意一種,上手react不難) 游戲規則 + 雙方各執一子,在九宮格內一方三子連成線則游戲結束 + 九宮格下滿未有三子連線則視為平局 "你可以點擊這 ...
  • 1.創建XMLHttpRequest let xhr=new XMLHttpRequest; 2.連接伺服器 xhr.open("get","goods.json",true) true代表非同步,false代表同步。goods.json代表請求的路徑 3.向伺服器發送請求 xhr.send() 4. ...
  • <script> //js獲取頁面所有搜索條件function GetSearchData(SearchDivID) { var ObjID= SearchDivID? SearchDivID: ".search"; //預設為類樣式.search, <div class="search"> var ...
  • VUE中CSS樣式穿透 1. 問題由來 在做兩款H5的APP項目,前期採用微信官方推薦的weui組件庫。後來因呈現的效果不理想,組件不豐富,最終項目完成後全部升級採用了有贊開發的 組件庫。同時將webpack順利從3升級到4(項目結構 webpack+vue+vuex+vue router+vant ...
  • 作者:西西 最近很流行的一句話成年人的世界沒有「容易」二字,其實程式員的世界更沒有『容易』二字。不是電腦專業出身的我初入行的時候,每晚在樓下的全時便利店敲代碼到深夜 1 - 2 點。但這其實僅僅是開始,努力了幾個月以後成功面試進入一家互聯網公司(剛入職場薪資很低),自此開啟了我的代碼職業生涯。 初 ...
  • BFC的生成 在實現CSS的佈局時,假設我們不知道BFC的話,很多地方我們生成了BFC但是不知道.在佈局中,一個元素是block元素還是inline元素是必須要知道的.而BFC就是用來格式化塊狀元素盒子,同樣還有管理內連盒子的IFC等.那首先就來瞭解一下什麼是FC. 既然BFC是一塊獨立的渲染區域, ...
  • JSP三大指令 一個jsp頁面中,可以有0~N個指令的定義! 1. page --> 最複雜:<%@page language="java" info="xxx"...%> * pageEncoding和contentType: > pageEncoding:它指定當前jsp頁面的編碼,只要不說謊, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...