国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

vuex 2.0 源碼解讀

yvonne / 2709人閱讀

摘要:至此它便作為一個唯一數(shù)據(jù)源而存在。改變中的狀態(tài)的唯一途徑就是顯式地提交。這樣使得可以方便地跟蹤每一個狀態(tài)的變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解應(yīng)用背后的基本思想,借鑒了和參考源碼解讀一架構(gòu)入門教程狀態(tài)管理

準(zhǔn)備工作 1.下載安裝運(yùn)行

這里以2.0.0-rc.6為例
官網(wǎng)github下載鏈接(對應(yīng)版本):https://github.com/vuejs/vuex...
點(diǎn)擊下載到本地
按照readme.md

$ npm install
$ npm run dev # serve examples at localhost:8080
2.example示例

查看package.json dev命令,

"dev": "node examples/server.js" 

打開http://localhost:8080/
examples里面的文件都能運(yùn)行了,
Counter,
Counter with Hot Reload,
Shopping Cart,
TodoMVC,
FluxChat 這些每一個有很有代表性

源碼 src/index.js

vuex 只暴露出了6個方法

export default {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions
}
1.install方法

install函數(shù)用于vue
vue.use() 里會調(diào)用自動install方法

function install (_Vue) {
  if (Vue) {
    console.error(
      "[vuex] already installed. Vue.use(Vuex) should be called only once."
    )
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}
  applyMixin(Vue){
    // ...
    function vuexInit () {
        const options = this.$options
        // store injection
        if (options.store) {
          this.$store = options.store
        } else if (options.parent && options.parent.$store) {
          this.$store = options.parent.$store
        }
      }
}

new Vue({store})傳進(jìn)去一個store對象,在new Vue()的時候?qū)ptions進(jìn)行了處理

    vm.$options.store =  store
    // 把傳入的對象除了$el都掛在了$options下
    // 參考vue源碼對options處理部分

這樣做

if (options.store) {
     // 這樣在 vue 里全局里通過 $store能夠訪問store對象
     this.$store = options.store
 } 
2.Store構(gòu)造函數(shù)
class Store {
  constructor (options = {}) {assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
    assert(typeof Promise !== "undefined", `vuex requires a Promise polyfill in this browser.`)
    // options解構(gòu)賦值
    const {
      state = {},
      plugins = [],
      strict = false
    } = options
    
    // store internal state
    this._options = options
    this._committing = false
    this._actions = Object.create(null)
    this._mutations = Object.create(null)
    this._wrappedGetters = Object.create(null)
    this._runtimeModules = Object.create(null)
    this._subscribers = []
    this._watcherVM = new Vue()

    // bind commit and dispatch to self
    const store = this
    // dispatch, commit 解構(gòu)賦值
    const { dispatch, commit } = this
    // dispatch改變this,使this為store
    this.dispatch = function boundDispatch (type, payload) {
      return dispatch.call(store, type, payload)
    }
    // 同上
    this.commit = function boundCommit (type, payload, options) {
      return commit.call(store, type, payload, options)
    }
    
    // 嚴(yán)格模式
    // strict mode 
    this.strict = strict
    
    // 對傳入module的處理
    // init root module.
    // this also recursively registers all sub-modules
    // and collects all module getters inside this._wrappedGetters
    installModule(this, state, [], options)

    // initialize the store vm, which is responsible for the reactivity
    // (also registers _wrappedGetters as computed properties)
    resetStoreVM(this, state)

    // apply plugins
    plugins.concat(devtoolPlugin).forEach(plugin => plugin(this))
    }
}
 get state () {
     //返回state,state掛在在stare.vm下
    return this._vm.state
  }

  set state (v) {
    //不能被外部改變,私有變量
    assert(false, `Use store.replaceState() to explicit replace store state.`)
  }
3.installModule函數(shù)

installModule(this, state, [], options)

function installModule (store, rootState, path, module, hot) {
 // 如果path為[]那么isRoot為tree
  const isRoot = !path.length
 // 把傳入的options請求解構(gòu)賦值,
  const {
    state,
    actions,
    mutations,
    getters,
    modules
  } = module

  // hot不存在而且path不為[]
  // set state
  if (!isRoot && !hot) {
    const parentState = getNestedState(rootState, path.slice(0, -1))
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      Vue.set(parentState, moduleName, state || {})
    })
  }

  if (mutations) {
    Object.keys(mutations).forEach(key => {
      registerMutation(store, key, mutations[key], path)
    })
  }

  if (actions) {
    Object.keys(actions).forEach(key => {
      registerAction(store, key, actions[key], path)
    })
  }

  if (getters) {
    wrapGetters(store, getters, path)
  }

  if (modules) {
    //注意 只有傳遞了modules 才會執(zhí)行if (!isRoot && !hot)后面的處理,這里對path.concat(key)進(jìn)行了處理
    Object.keys(modules).forEach(key => {
      installModule(store, rootState, path.concat(key), modules[key], hot)
    })
  }
}

這里有個很重要的概念要理解,什么是 path. vuex 的一個 store 實(shí)例可以拆分成很多個 module ,不同的 module 可以理解成一個子代的 store 實(shí)例(事實(shí)上,module 確實(shí)和 store 具有一樣的結(jié)構(gòu)),這是一種模塊化的概念。因此這里的 path 可以理解成是表示一種層級關(guān)系(樹狀),當(dāng)你有了一個 root state 之后,根據(jù)這個 root state 和 path 可以找到 path 路徑對應(yīng)的一個 local state, 每一個 module 下的 mutations 和 actions 改變的都是這個local state,而不是 root state.

看一下 getNestedState方法

/*
 * state: Object, path: Array
 * 假設(shè)path = ["a", "b", "c"]
 * 函數(shù)返回結(jié)果是state[a][b][c]
 */
function getNestedState (state, path) {
  return path.length
    ? path.reduce(function (state, key) { return state[key]; }, state)
    : state
}

這里學(xué)習(xí)一下reduce的妙用 reduce不清楚的 mdn傳送門點(diǎn)我

 /** handler是傳入的mutation[key]方法比如
   increment (state) {
       state.count++
   },
   decrement (state) {
       state.count--
   }
   type就是key increment, decrement
  **/

registerMutation函數(shù)
----------------

function registerMutation (store, type, handler, path = []) {
  const entry = store._mutations[type] || (store._mutations[type] = [])
  entry.push(function wrappedMutationHandler (payload) {
    handler(getNestedState(store.state, path), payload)
  })
}

所有的 mutations 都經(jīng)過處理后,保存在了 store._mutations 對象里。 _mutations 的結(jié)構(gòu)為

_mutations: {
    increment: [function wrappedMutationHandler(payload){increment(store.state.modules){...}}, ...],
    decrement: [function wrappedMutationHandler(payload){decrement(store.state.modules, payload){...}}, ...],
    ...
}

這個對應(yīng)第一個參數(shù)為該模塊下的state對象,如果沒有modules就是rootState,
第二個參數(shù)就是payload 用戶自定義傳遞的參數(shù)

     increment (state) 
        state.count++
      },
      decrement (state) {
        state.count--
      }

同理

4.registerAction函數(shù)
function registerAction (store, type, handler, path = []) {
  const entry = store._actions[type] || (store._actions[type] = [])
  const { dispatch, commit } = store
  entry.push(function wrappedActionHandler (payload, cb) {
    let res = handler({
      dispatch,
      commit,
      getters: store.getters,
      state: getNestedState(store.state, path),
      rootState: store.state
    }, payload, cb)
    if (!isPromise(res)) {
      // 返回 Promise
      res = Promise.resolve(res)
    }
    if (store._devtoolHook) {
      return res.catch(err => {
        store._devtoolHook.emit("vuex:error", err)
        throw err
      })
    } else {
      return res
    }
  })
}

被處理成

_actions: {
    increment: [function wrappedActionHandler(payload){increment({
      dispatch,
      commit,
      getters: store.getters,
      state: getNestedState(store.state, path),
      rootState: store.state
    }){...}}, ...],
    decrement: [function wrappedActionHandler(payload){decrement({
      dispatch,
      commit,
      getters: store.getters,
      state: getNestedState(store.state, path),
      rootState: store.state
    }, payload){...}}, ...],
    ...
}

第一個參數(shù)傳入一個對象,所以才能使用commit方法

const actions = {
  increment: ({ commit }) => commit("increment"),
  decrement: ({ commit }) => commit("decrement")
}
5.commit和dispatch

commit為同步,dispatch為異步,當(dāng)所有執(zhí)行完畢返回Promise

commit (type, payload, options) {
    // check object-style commit
    if (isObject(type) && type.type) {
      options = payload
      payload = type
      type = type.type
    }
    const mutation = { type, payload }
    const entry = this._mutations[type]
    if (!entry) {
      console.error(`[vuex] unknown mutation type: ${type}`)
      return
    }
    this._withCommit(() => {
      entry.forEach(function commitIterator (handler) {
        handler(payload)
      })
    })
    if (!options || !options.silent) {
      this._subscribers.forEach(sub => sub(mutation, this.state))
    }
  }

  dispatch (type, payload) {
    // check object-style dispatch
    if (isObject(type) && type.type) {
      payload = type
      type = type.type
    }
    const entry = this._actions[type]
    if (!entry) {
      console.error(`[vuex] unknown action type: ${type}`)
      return
    }
    return entry.length > 1
      ? Promise.all(entry.map(handler => handler(payload)))
      : entry[0](payload)
  }
6.wrapGetters
// store增加一個 _wrappedGetters 屬性
function wrapGetters (store, moduleGetters, modulePath) {
  Object.keys(moduleGetters).forEach(getterKey => {
    const rawGetter = moduleGetters[getterKey]
    if (store._wrappedGetters[getterKey]) {
      console.error(`[vuex] duplicate getter key: ${getterKey}`)
      return
    }
    store._wrappedGetters[getterKey] = function wrappedGetter (store) {
      return rawGetter(
        getNestedState(store.state, modulePath), // local state
        store.getters, // getters
        store.state // root state
      )
    }
  })
}

注意 這里的所有 getters 都儲存在了全局的一個 _wrappedGetters 對象中,同樣屬性名是各個 getterKey ,屬性值同樣是一個函數(shù),執(zhí)行這個函數(shù),將會返回原始 getter 的執(zhí)行結(jié)果。

7.resetStoreVM
function resetStoreVM (store, state) {
  const oldVm = store._vm

  //...
  Object.keys(wrappedGetters).forEach(key => {
    const fn = wrappedGetters[key]
    // use computed to leverage its lazy-caching mechanism
    computed[key] = () => fn(store)
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })

   //...
  store._vm = new Vue({
    data: { state },
    computed
  })

  if (oldVm) {
    // dispatch changes in all subscribed watchers
    // to force getter re-evaluation.
    store._withCommit(() => {
      oldVm.state = null
    })
    Vue.nextTick(() => oldVm.$destroy())
  }
}

著重講一下最重要的

store._vm = new Vue({
    data: { state },
    computed
  })

state是放在vue實(shí)例對象的 this.data.state 里面的
這個 new Vue 和你平常的new Vue不一樣,這是兩個vue實(shí)例,數(shù)據(jù)不共用
之所以掛在在vue是方便使用vue的一些方法nextTick,set等,更方便控制state狀態(tài)
所以在vue組件里如果不寫

computed:{
     ...mapState(["count"])
 },

就不能直接寫 template 里寫{{count}} 而必須使用 this.$store.state.count

map輔助函數(shù) normalizeMap
/*
 * 如果map是一個數(shù)組 ["type1", "type2", ...]
 * 轉(zhuǎn)化為[
 *   {
 *     key: type1,
 *     val: type1
 *   },
 *   {
 *     key: type2,
 *     val: type2
 *   },
 *   ...
 * ]
 * 如果map是一個對象 {type1: fn1, type2: fn2, ...}
 * 轉(zhuǎn)化為 [
 *   {
 *     key: type1,
 *     val: fn1
 *   },
 *   {
 *     key: type2,
 *     val: fn2
 *   },
 *   ...
 * ]
 */
function normalizeMap (map) {
  return Array.isArray(map)
    ? map.map(function (key) { return ({ key: key, val: key }); })
    : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
}

normalizeMap 函數(shù)接受一個對象或者數(shù)組,最后都轉(zhuǎn)化成一個數(shù)組形式,數(shù)組元素是包含 key 和 value 兩個屬性的對象。

map
export function mapState (states) {
  const res = {}
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState () {
      return typeof val === "function" //是函數(shù),執(zhí)行返回結(jié)果
        ? val.call(this, this.$store.state, this.$store.getters)
        : this.$store.state[val] // 不是,返回$store.state[val]值
    }
  })
  return res
}

export function mapMutations (mutations) {
  const res = {}
  normalizeMap(mutations).forEach(({ key, val }) => {
    res[key] = function mappedMutation (...args) {
      // 通過commit執(zhí)行Mutation里的函數(shù)和自己用$store.commit()執(zhí)行結(jié)果是一樣,定義一個方法,用戶使用起來更方便
      return this.$store.commit.apply(this.$store, [val].concat(args))
    }
  })
  return res
}
//這里 getters 同樣接受一個數(shù)組,同樣返回一個對象
export function mapGetters (getters) {
  const res = {}
  normalizeMap(getters).forEach(({ key, val }) => {
    res[key] = function mappedGetter () {
      if (!(val in this.$store.getters)) {
        console.error(`[vuex] unknown getter: ${val}`)
      }
      return this.$store.getters[val]
    }
  })
  return res
}


export function mapActions (actions) {
  const res = {}
  normalizeMap(actions).forEach(({ key, val }) => {
    res[key] = function mappedAction (...args) {
     // 同mapMutations
      return this.$store.dispatch.apply(this.$store, [val].concat(args))
    }
  })
  return res
}

map* 方法,這四種方法可以都返回一個對象,所以在vue里我們能夠使用...

computed:{
     ...mapState(["count"])
 }
小結(jié)

【單一狀態(tài)樹】
vuex 使用單一狀態(tài)樹——用一個對象就包含了全部的應(yīng)用層級狀態(tài)。至此它便作為一個“唯一數(shù)據(jù)源 (SSOT)”而存在。這也意味著,每個應(yīng)用將僅僅包含一個 store 實(shí)例。單一狀態(tài)樹能夠直接地定位任一特定的狀態(tài)片段,在調(diào)試的過程中也能輕易地取得整個當(dāng)前應(yīng)用狀態(tài)的快照

每一個 Vuex 應(yīng)用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含著應(yīng)用中大部分的狀態(tài) (state)。Vuex 和單純的全局對象有以下兩點(diǎn)不同:

  1、Vuex 的狀態(tài)存儲是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會相應(yīng)地得到高效更新

  2、不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得可以方便地跟蹤每一個狀態(tài)的變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解應(yīng)用
Vuex 背后的基本思想,借鑒了 Flux、Redux和 The Elm Architecture

參考
vuex 2.0源碼解讀(一)
Flux 架構(gòu)入門教程
Vue狀態(tài)管理vuex

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98370.html

相關(guān)文章

  • vuex 2.0源碼解讀(一)

    摘要:簡單點(diǎn)說,當(dāng)你使用構(gòu)造函數(shù),它實(shí)際上做了這么幾件事,首先定義給實(shí)例定義一些內(nèi)部屬性,之后就是綁定和的上下文對象永遠(yuǎn)是實(shí)例上,之后根據(jù)傳入的充實(shí)內(nèi)部狀態(tài)等等。函數(shù)執(zhí)行的結(jié)果是返回一個對象,屬性名對應(yīng)于傳入的對象或者數(shù)組元素。 轉(zhuǎn)載請注明出處 https://segmentfault.com/a/11... vuex2.0 和 vuex1.x 相比,API改變的還是很多的,但基本思想沒什么...

    luqiuwen 評論0 收藏0
  • vue服務(wù)端渲染demo將vue-cli生成的項目轉(zhuǎn)為ssr

    摘要:無需使用服務(wù)器實(shí)時動態(tài)編譯,而是使用預(yù)渲染方式,在構(gòu)建時簡單地生成針對特定路由的靜態(tài)文件。與可以部署在任何靜態(tài)文件服務(wù)器上的完全靜態(tài)單頁面應(yīng)用程序不同,服務(wù)器渲染應(yīng)用程序,需要處于運(yùn)行環(huán)境。更多的服務(wù)器端負(fù)載。 目錄結(jié)構(gòu) -no-ssr-demo 未做ssr之前的項目代碼用于對比 -vuecli2ssr 將vuecli生成的項目轉(zhuǎn)為ssr -prerender-demo 使用prer...

    whinc 評論0 收藏0
  • 【前端詞典】從源碼解讀 Vuex 注入 Vue 生命周期的過程

    摘要:第一篇文章我會結(jié)合和的部分源碼,來說明注入生命周期的過程。說到源碼,其實(shí)沒有想象的那么難。但是源碼的調(diào)用樹會復(fù)雜很多。應(yīng)用的業(yè)務(wù)代碼逐漸復(fù)雜,事件事件總線等通信的方式的弊端就會愈發(fā)明顯。狀態(tài)管理是組件解耦的重要手段。前言 這篇文章是【前端詞典】系列文章的第 13 篇文章,接下的 9 篇我會圍繞著 Vue 展開,希望這 9 篇文章可以使大家加深對 Vue 的了解。當(dāng)然這些文章的前提是默認(rèn)你對 ...

    Aklman 評論0 收藏0
  • vuex入門,詳細(xì)的講解

    摘要:學(xué)習(xí),首先明白是什么是一個專為應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。 學(xué)習(xí)vuex,首先明白vuex是什么?Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。 如果你在使用 vue.js , 那么我...

    jsummer 評論0 收藏0
  • Vuex — The core of Vue application

    摘要:個人看來,一個狀態(tài)管理的應(yīng)用,無論是使用,還是,最困難的部分是在的設(shè)計。中,并沒有移除,而是改為用于觸發(fā)。也是一個對象,用于注冊,每個都是一個用于返回一部分的。接受一個數(shù)組或?qū)ο螅鶕?jù)相應(yīng)的值將對應(yīng)的綁定到組件上。 系列文章: Vue 2.0 升(cai)級(keng)之旅 Vuex — The core of Vue application (本文) 從單頁應(yīng)用(SPA)到服務(wù)器...

    Aldous 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<