溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

vue處理響應(yīng)式數(shù)據(jù)的方法是什么

發(fā)布時間:2023-03-29 09:09:19 來源:億速云 閱讀:61 作者:iii 欄目:編程語言

這篇“vue處理響應(yīng)式數(shù)據(jù)的方法是什么”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“vue處理響應(yīng)式數(shù)據(jù)的方法是什么”文章吧。

vue處理響應(yīng)式數(shù)據(jù)的方法是什么

那繼續(xù)下一個問題。

vue處理響應(yīng)式數(shù)據(jù)的方法是什么

這個回答感覺就比較官方了,沒有回答到我想要的答案。

理由其實很簡單,因為proxy方法不能代理值類型,只能代理對象。所以需要一個額外的方法,來處理值類型的數(shù)據(jù)。

當(dāng)然你也可以一個ref走天下,vue源碼做了兼容會自動進(jìn)行轉(zhuǎn)換

有了這些理解之后,我們來看今天的重頭戲,自己仿照vue3源碼,實現(xiàn)一個響應(yīng)式系統(tǒng)。

相關(guān)代碼可以點擊查看,根據(jù)文章的標(biāo)題選擇不同的分支即可。

實現(xiàn)reactive

在前文我們也介紹了,reactive其實用的是proxy代理對象。

我們可以使用proxy實現(xiàn)一個簡單的代理函數(shù)reactive。

      function reactive(target) {        const isObject = (val) =>  val !== null && typeof val === 'object'

        if (!isObject(target)) {          console.warn(`數(shù)據(jù)必須是對象: ${String(target)}`)          return target
        }        const proxy = new Proxy(target, {          get: (target, key, receiver) => {            console.log('get', key)            const res = Reflect.get(target, key, receiver)            // track(target, key)
            // 這句很關(guān)鍵,不然嵌套數(shù)據(jù),里面的不會響應(yīng)
            if (isObject(res)) {              return reactive(res)
            }            return res
          },          set: (target, key, value, receiver) => {            console.log('set', key, value)            const result = Reflect.set(target, key, value, receiver)            // trigger(target, key, value)
            return result
          },          deleteProperty: () => {            const result = Reflect.deleteProperty(target, key)            return result
          }
        })        return proxy
      }      const person = reactive({        name: '',        age: 18,        like: ['apple']
      })

      person.name  = 'vue test'復(fù)制代碼

注意:Reflect

Reflect.get(target, key)跟直接訪問target[key]是有一點差別的。

當(dāng)代理對象中,有g(shù)et,set等this指向的時候,可以重定向this。

舉個例子:

        const person = new Proxy({            name: "vue test",            age: 18,            get info() {                return 'name is :' + this.name + ' age is:' + this.age
            }
        }, {            get: (target, key, receiver) => {                console.log('get', key)                // return target[key]
                return Reflect.get(target, key, receiver)
            }
        })        console.log(person.info)復(fù)制代碼

使用Reflect,我們在訪問name, age的時候均可以觸發(fā)。vue處理響應(yīng)式數(shù)據(jù)的方法是什么

改成target之后,則只會在info觸發(fā)一次。

return target[key]復(fù)制代碼

vue處理響應(yīng)式數(shù)據(jù)的方法是什么

實現(xiàn)ref

在vue3中,ref是通過get和set來實現(xiàn)的。

跟上面類似,也還是先聲明一個函數(shù),然后通過get,set來訪問數(shù)據(jù)。

      function ref(value) {        return new RefImpl(value)
      }      class RefImpl {        constructor(value) {          // 如果值是對象,則用reactive處理
          this._value = isObject(value) ? reactive(value) : value          // 記錄一下初始值
          this._rawValue = value
        }        get value() {          // trackRefValue(this)
          return this._value
        }        set value(newVal) {          if (!Object.is(newVal, this._rawValue)) {            // 更新原始數(shù)據(jù)
            this._rawValue = newVal            // 更新 .value 的值
            this._value = isObject(newVal) ? reactive(newVal) : value            // triggerRefValue(this)
          }
        }
      }復(fù)制代碼

源碼也很直觀的解釋了,為什么ref的使用一定要用.value的方式使用,因為get/set就是通過value來設(shè)置的。

添加依賴收集與觸發(fā)

數(shù)據(jù)代理我們已經(jīng)完成了,但是數(shù)據(jù)更改之后,怎么通知組件實現(xiàn)雙向綁定呢?

答案就是依賴收集與觸發(fā),也就是當(dāng)觸發(fā)get的時候,我把觸發(fā)get的這個條件【函數(shù)】給保存起來,當(dāng)觸發(fā)set的時候,重新執(zhí)行一下觸發(fā)一下這個條件【函數(shù)】不就行了嗎。

還是來看代碼,我加一個track收集的方法,加一個target觸發(fā)的方法。(也就是上面代碼片段注釋掉的兩行代碼)

除此之外,還需要一個effect函數(shù)來管理觸發(fā)函數(shù)。

      let activeEffect = null
      const targetMap = new WeakMap()      // 依賴收集/觸發(fā)
      function track(target, key) {        let depsMap = targetMap.get(target)        if (!depsMap) {
          targetMap.set(target, (depsMap = new Map()))
        }        let dep = depsMap.get(key)        if (!dep) {
          dep = new Set()
        }
        dep.add(activeEffect)
        depsMap.set(key, dep)
      }      function trigger(target, key, value) {        const depsMap = targetMap.get(target)        if (!depsMap) {          return
        }        const deps = depsMap.get(key)        if (!deps) {          return
        }

        deps.forEach(effectFn => {          if (effectFn.scheduler) {
            effectFn.scheduler()
          } else {            effectFn()
          }
        })
      }      function effect(fn,options = {}) {        const effectFn = () => {          try {
            activeEffect = effectFn            return fn()
          } catch (error) {
            activeEffect = null
          }
        }        if (!options.lazy) {          effectFn()
        }
        effectFn.scheduler = options.scheduler
        return effectFn
      }      const person = reactive({        name: "hello world"
      })      effect(() => {        console.log('effect person', person.name)
      })      setTimeout(() => {
        person.name = 'setTimeout world'
      }, 2000)復(fù)制代碼

activeEffect用來存觸發(fā)的條件函數(shù)。

targetMap用來存放依賴字典,格式如下

{
    target: {
        key: []
    }
}復(fù)制代碼

輸出結(jié)果為hello world,2秒之后,重新執(zhí)行依賴性函數(shù),輸出setTimeout world

vue處理響應(yīng)式數(shù)據(jù)的方法是什么

總結(jié)

數(shù)據(jù)的代理并不復(fù)雜,就是在proxy的基礎(chǔ)上,加上一些邊界處理。而要實現(xiàn)響應(yīng)式則需要加上依賴收集,依賴觸發(fā)的實現(xiàn)。

effect是一個很重要的函數(shù),很多api是基于這個函數(shù)開發(fā)的,比如useEffect, watch。組件的更新也是基于effect函數(shù),這個后續(xù)還會提到。

如果不太理解effect,可以梳理一下執(zhí)行順序。

  • 1.調(diào)用effect函數(shù),并傳入?yún)?shù)fn

  • 2.申明一個effectFn函數(shù),并執(zhí)行,將函數(shù)保存為activeEffect

  • 3.執(zhí)行fn,讀取person.name

  • 4.走proxy的get代理

  • 5.收集依賴,將activeEffect保存的函數(shù)存到全局map中

  • 6.此時,effect函數(shù)執(zhí)行完畢,等待數(shù)據(jù)更新

  • 7.2s后,走proxy的set代理

  • 8.執(zhí)行全局map中保存的函數(shù),重新執(zhí)行effect函數(shù),再次回到步驟1

相關(guān)代碼可以點擊查看,選擇lesson3分支即可。

文章相關(guān)代碼,可在vue/examples中查看,仿vue實現(xiàn)版本可在packages/reactivity中查看。

以上就是關(guān)于“vue處理響應(yīng)式數(shù)據(jù)的方法是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI