Vue provide/inject 部分源碼分析 實現響應式數據更新

下面是我本身曾經遇到 一個問題,直接以本身QA的形式來寫吧前端

官網給出實例,說自己是不支持數據響應式的, 可是能夠傳入響應式數據,那麼provide,inject就能夠實現響應式segmentfault

我這裏理解應該沒錯哈,有不對的地方請指出。數組

我本身寫的demo,作了以下更改緩存

parent 頁面:bash

export default {
        provide(){
         return   {foo:this.fonnB}
        },
        data(){
          return {fonnB:'old word'}   
        }
         created() {
          setTimeout(()=>{
            this.fonnB="new words";    // 這種跟新,僅僅foonB變化了,foo沒有變化
            this._provided.foo="new words"; 
            //這種更新 foo變化了,但子組件得到的foo  依舊是old words
            console.log( this._provided)
          },1000)

        },

      }
複製代碼

child頁面:ide

export default {
        inject:['foo'],
        data(){
          return {chilrfoo:this.foo}   
        }    
      }
複製代碼
經過上面2個方法,通過驗證,子組件頁面都沒辦法實現響應更新this.foo的值。
 求解釋,謝謝
複製代碼

以上是我本身的問題, 下面是我基本理解後,在本身回答的問題函數

現作了以下修改,能夠達到父親組件改變,下面的孫子組件都能更新數據.這樣就是傳入了一個響應式數據,若是須要雙向數據的話,須要在child頁面的computed 中手動寫set 函數,computed 自己就只至關於一個get函數。ui

值得注意是:child頁面data 數據中childfooOld並不會響應。這個點還沒搞懂。this

parent頁面:spa

export default {

provide(){
     return   {foo:this.fonnB}
    },
    data(){
      return {
      fonnB:{a:'old word'}
      }   
    }
     created() {
      setTimeout(()=>{
        this.fonnB.a="new words";    

        //這種更新 foo變化了,但子組件得到的foo  依舊是old words

      },1000)

    },

  }
複製代碼

child頁面:

export default {
    inject:['foo'],
    data(){
      return {
       childfooOld:this.foo.a
      }   
    },
    computed:{
        chilrfoo(){
            return  this.foo.a
        }
    }    
  }
複製代碼

關於prodive 和inject 源碼部分以下

export function initInjections (vm: Component) {

const result = resolveInject(vm.$options.inject, vm)

if (result) {

observerState.shouldConvert = false
Object.keys(result).forEach(key => {
  defineReactive(vm, key, result[key])
})
observerState.shouldConvert = true</pre>

}

}
複製代碼

能夠看出 prodive 也運用了defineReactive 函數,增長了自身的set,get函數,也是響應式數據,以下圖

以下 是inject 源碼,我沒看出來那裏明確增長了set/get,可是打印出來結果inject 也是有set/get的

export function resolveInject (inject: any, vm: Component): ?Object {

if (inject) {

// inject 是 :any 類型由於流沒有智能到可以指出緩存
const result = Object.create(null)
// 獲取 inject 選項的 key 數組
const keys = hasSymbol
  ? Reflect.ownKeys(inject).filter(key => {
    /* istanbul ignore next */
    return Object.getOwnPropertyDescriptor(inject, key).enumerable
  })
  : Object.keys(inject)

for (let i = 0; i < keys.length; i++) {
  const key = keys[i]
  const provideKey = inject[key].from
  let source = vm
  while (source) {
    if (source._provided && provideKey in source._provided) {
      result[key] = source._provided[provideKey]
      break
    }
    source = source.$parent
  }
  if (!source) {
    if ('default' in inject[key]) {
      const provideDefault = inject[key].default
      result[key] = typeof provideDefault === 'function'
        ? provideDefault.call(vm)
        : provideDefault
    } else if (process.env.NODE_ENV !== 'production') {
      warn(`Injection "${key}" not found`, vm)
    }
  }
}
return result

}

}
複製代碼

經過computed 就實現了上下傳值,我的疑問就是  child頁面,直接把foo 綁定到data屬性下,foo變化時,child中的data不變化。。 按道理,data中有get/set ,應該也是響應的,求大神分享 發現文章中的錯誤,或者有更好的建議,歡迎評論或進前端全棧羣:866109386,來交流討論吹水。

下面是我本身曾經遇到 一個問題,直接以本身QA的形式來寫吧

自問自答了,須要的同窗也能夠直接訪問 segmentfault地址

官網給出實例,說自己是不支持數據響應式的, 可是能夠傳入響應式數據,那麼provide,inject就能夠實現響應式。

我這裏理解應該沒錯哈,有不對的地方請指出。

我本身寫的demo,作了以下更改

parent 頁面:

export default {
        provide(){
         return   {foo:this.fonnB}
        },
        data(){
          return {fonnB:'old word'}   
        }
         created() {
          setTimeout(()=>{
            this.fonnB="new words";    // 這種跟新,僅僅foonB變化了,foo沒有變化
            this._provided.foo="new words"; 
            //這種更新 foo變化了,但子組件得到的foo  依舊是old words
            console.log( this._provided)
          },1000)

        },

      }
複製代碼

child頁面:

export default {
        inject:['foo'],
        data(){
          return {chilrfoo:this.foo}   
        }    
      }
複製代碼
經過上面2個方法,通過驗證,子組件頁面都沒辦法實現響應更新this.foo的值。
 求解釋,謝謝
複製代碼

以上是我本身的問題, 下面是我基本理解後,在本身回答的問題

現作了以下修改,能夠達到父親組件改變,下面的孫子組件都能更新數據.這樣就是傳入了一個響應式數據,若是須要雙向數據的話,須要在child頁面的computed 中手動寫set 函數,computed 自己就只至關於一個get函數。

值得注意是:child頁面data 數據中childfooOld並不會響應。這個點還沒搞懂。

parent頁面:

export default {

provide(){
     return   {foo:this.fonnB}
    },
    data(){
      return {
      fonnB:{a:'old word'}
      }   
    }
     created() {
      setTimeout(()=>{
        this.fonnB.a="new words";    

        //這種更新 foo變化了,但子組件得到的foo  依舊是old words

      },1000)

    },

  }
複製代碼

child頁面:

export default {
    inject:['foo'],
    data(){
      return {
       childfooOld:this.foo.a
      }   
    },
    computed:{
        chilrfoo(){
            return  this.foo.a
        }
    }    
  }
複製代碼

關於prodive 和inject 源碼部分以下

export function initInjections (vm: Component) {

const result = resolveInject(vm.$options.inject, vm)

if (result) {

observerState.shouldConvert = false
Object.keys(result).forEach(key => {
  defineReactive(vm, key, result[key])
})
observerState.shouldConvert = true</pre>

}

}
複製代碼

能夠看出 prodive 也運用了defineReactive 函數,增長了自身的set,get函數,也是響應式數據,以下圖

以下 是inject 源碼,我沒看出來那裏明確增長了set/get,可是打印出來結果inject 也是有set/get的

export function resolveInject (inject: any, vm: Component): ?Object {

if (inject) {

// inject 是 :any 類型由於流沒有智能到可以指出緩存
const result = Object.create(null)
// 獲取 inject 選項的 key 數組
const keys = hasSymbol
  ? Reflect.ownKeys(inject).filter(key => {
    /* istanbul ignore next */
    return Object.getOwnPropertyDescriptor(inject, key).enumerable
  })
  : Object.keys(inject)

for (let i = 0; i < keys.length; i++) {
  const key = keys[i]
  const provideKey = inject[key].from
  let source = vm
  while (source) {
    if (source._provided && provideKey in source._provided) {
      result[key] = source._provided[provideKey]
      break
    }
    source = source.$parent
  }
  if (!source) {
    if ('default' in inject[key]) {
      const provideDefault = inject[key].default
      result[key] = typeof provideDefault === 'function'
        ? provideDefault.call(vm)
        : provideDefault
    } else if (process.env.NODE_ENV !== 'production') {
      warn(`Injection "${key}" not found`, vm)
    }
  }
}
return result

}

}
複製代碼

經過computed 就實現了上下傳值,我的疑問就是  child頁面,直接把foo 綁定到data屬性下,foo變化時,child中的data不變化。。 按道理,data中有get/set ,應該也是響應的,求大神分享 發現文章中的錯誤,或者有更好的建議,歡迎評論或進前端全棧羣:866109386,來交流討論吹水。

相關文章
相關標籤/搜索