Grandes notes d'étude frontale - Principe du système réactif Vue.js 3.0

Principe du système réactif Vue.js 3.0

Source de sortie du contenu de l'article: grand camp d'entraînement haut de gamme

1. Introduction

1. Revue réactive de Vue.js

  • L'objet proxy implémente la surveillance des propriétés
  • Imbrication d'attributs à plusieurs niveaux, traitement du niveau suivant d'attributs dans le processus d'accès aux attributs
  • Les propriétés ajoutées dynamiquement sont surveillées par défaut
  • L'opération de suppression de l'attribut de surveillance par défaut
  • Propriété d'index et de longueur du tableau de surveillance par défaut
  • Peut être utilisé comme module séparé

2. Fonctions essentielles

  • eactive / ref / toRefs / calculé
  • effet
  • Piste
  • déclencheur

Deux, examen des objets proxy

1. En mode strict, la fonction Proxy doit renvoyer une valeur booléenne, sinon elle signalera une TypeError

Uncaught TypeError: 'set' on proxy: trap retourné falsish pour la propriété 'foo'

'use strict'
// 问题1: set和deleteProperty中需要返回布尔类型的值
// 严格模式下,如果返回false的话,会出现TypeError的异常
const target = {
    
    
  foo: 'xxx',
  bar: 'yyy'
}
// Reflect.getPrototypeOf()
// Object.getPrototypeOf()
const proxy = new Proxy(target, {
    
    
  get (target, key, receiver) {
    
    
    // return target[key]
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    
    
    // target[key] = value
    return Reflect.set(target, key, value, receiver) // 这里得写return
  },
  deleteProperty(target, key) {
    
    
    // delete target[key]
    return Reflect.deleteProperty(target, key) // 这里得写return
  }
})

proxy.foo = 'zzz'

2. Utilisez le récepteur dans Proxy et Reflect

Receiver dans Proxy: Proxy ou un objet
qui hérite du Proxy Receiver dans React: Si l'objet cible a un getter, celui-ci dans le getter pointe vers le receveur

const obj = {
    
    
  get foo () {
    
    
    console.log(this)
    return this.bar
  }
}

const proxy = new Proxy(obj, {
    
    
  get(target, key, receiver) {
    
    
    if (key === 'bar') {
    
    
      return 'value - bar'
    }
    return Reflect.get(target, key, receiver) // 执行this.bar的时候,this指向代理对象,也就是获取target.bar
  }
})
console.log(proxy.foo) // value - bar

S'il est return Reflect.get(target, key, receiver)écrit return Reflect.get(target, key), le this dans l'attribut responsive foo pointe toujours vers l'objet d'origine obj, this.bar n'est pas défini, et une fois que le récepteur est passé, l'attribut this dans l'attribut responsive pointe vers le nouveau proxy d'objet réactif, this.bar Retour value - bar.

三 、 réactif

  • Accepter un paramètre, déterminer si ce paramètre est un objet
  • Créer un gestionnaire d'objet d'intercepteur, définir get / set / deleteProperty
  • Renvoyer l'objet Proxy

Réalisez réactif par vous-même

function isObject(value) {
    
    
  return value !== null && typeof value === 'object'
}

function convert(target) {
    
    
  return isObject(target) ? reactive(target) : target
}

const hasOwnProperty = Object.prototype.hasOwnProperty

function hasOwn(target, key) {
    
    
  return hasOwnProperty.call(target, key)
}

export function reactive(target) {
    
    
  if (!isObject(target)) return target

  const handler = {
    
    
    get (target, key, receiver) {
    
    
      // 收集依赖
      // track(target, key) // 稍后解注释
      console.log('get', key)
      const ret = Reflect.get(target, key, receiver)
      return convert(ret)
    },
    set (target, key, value, receiver) {
    
    
      const oldValue = Reflect.get(target, key, receiver)
      let ret = true
      if (oldValue !== value) {
    
    
        ret = Reflect.set(target, key, value, receiver)
        // 触发更新
        // trigger(target, key) // 稍后解注释
				console.log('set', key, value)
      }
      return ret
    },
    deleteProperty (target, key) {
    
    
      const hasKey = hasOwn(target, key)
      const ret = Reflect.deleteProperty(target, key)
      if (hasKey && ret) {
    
    
        // 触发更新
        // trigger(target, key) // 稍后解注释
				console.log('detele', key)
      }
      return ret
    }
  }

  return new Proxy(target, handler)
}

utilisation:

<body>
  <script type="module">
    import {
     
      reactive } from './reactivity/index.js'
    const obj = reactive({
     
     
      name: 'zs',
      age: 18
    })
    obj.name = 'lisi'
    delete obj.age
    console.log(obj)
  </script>
</body>

La sortie est:

définir le nom lisi
index.js: 39 detele age
index.html: 17 Proxy {name: “lisi”}

Quatrièmement, collectez les dépendances

Insérez la description de l'image ici

Cinq, effet, piste

let activeEffect = null
export function effect(callback) {
    
    
  activeEffect = callback
  callback() // 访问响应式对象的属性,去收集依赖
  activeEffect = null
}

let targetMap = new WeakMap()
export function track(target, key) {
    
     // 收集依赖
  if (!activeEffect)return
  let depsMap = targetMap.get(target)
  if(!depsMap) {
    
    
    targetMap.set(target, depsMap = new Map())
  }
  let dep = depsMap.get(key)
  if(!dep) {
    
    
    depsMap.set(key, dep = new Set())
  }
  dep.add(activeEffect)
}

Six, déclencheur

export function trigger(target, key) {
    
     // 触发依赖
  const depsMap = targetMap.get(target)
  if(!depsMap)return
  const dept = depsMap.get(key)
  if(dept) {
    
    
    dept.forEach(effect => {
    
    
      effect()
    })
  }
}

utilisation:

<body>
  <script type="module">
    import {
     
      reactive, effect } from './reactivity/index.js'
    const product = reactive({
     
     
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    let total = 0
    effect(() => {
     
     
      total = product.price * product.count
    })
    console.log(total) // 15000

    product.price = 4000
    console.log(total) // 12000

    product.count = 1
    console.log(total) // 4000
  </script>
</body>

Sept, réf

eactive vs ref

  • ref peut convertir des types de données de base en objets réactifs

  • L'objet retourné par ref est également sensible à la réaffectation à un objet

  • Objet renvoyé par réactif, la réaffectation perd de réactif

  • L'objet retourné par réactif ne peut pas être déconstruit

  • réactif

    const product = reactive({
          
          
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    
  • réf

    const price = ref(5000)
    const count = ref(3)
    

Mettre en œuvre réf:

export function ref(raw) {
    
    
  // 判断raw是否是ref创建的对象,如果是的话直接返回
  if (isObject(raw) && raw.__v_isRef)return

  let value = convert(raw)
  const r = {
    
    
    __v_isRef: true,
    get value () {
    
    
      track(r, 'value')
      return value
    },
    set value (newValue) {
    
    
      if(newValue !== value) {
    
    
        raw = newValue
        value = convert(raw)
        trigger(r, 'value')
      }
    }
  }
  return r
}

utilisation:

<body>
  <script type="module">
    import {
     
      reactive, effect, ref } from './reactivity/index.js'
    const price = ref(5000)
    const count = ref(3)
    let total = 0
    effect(() => {
     
     
      total = price.value * count.value
    })
    console.log(total) // 15000

    price.value = 4000
    console.log(total) // 12000

    count.value = 1
    console.log(total) // 4000
  </script>
</body>

Huit, toRefs

export function toRefs(proxy) {
    
    
  const ret = proxy instanceof Array ? new Array(proxy.length) : {
    
    }
  for (const key in proxy) {
    
    
    ret[key] = toProxyRef(proxy, key)
  }
  return ret
}

function toProxyRef(proxy, key) {
    
    
  const r = {
    
    
    __v_isRef: true,
    get value () {
    
    
      return proxy[key]
    },
    set value (newValue) {
    
    
      proxy[key] = newValue
    }
  }
  return r
}

utilisation

<body>
  <script type="module">
    import {
     
      reactive, effect, toRefs } from './reactivity/index.js'
    function useProduct() {
     
     
      const product = reactive({
     
     
        name: 'iPhone',
        price: 5000,
        count: 3
      })
      return toRefs(product) // 直接返回解构的product不是响应式对象,所以调用toRefs将reactive对象的每个属性都转化成ref对象
    }

    const {
     
      price, count } = useProduct()

    let total = 0
    effect(() => {
     
     
      total = price.value * count.value
    })
    console.log(total) // 15000

    price.value = 4000
    console.log(total) // 12000

    count.value = 1
    console.log(total) // 4000
  </script>
</body>

Neuf, calculé

export function computed(getter) {
    
    
  const result = ref()
  effect(() => (result.value = getter()))
  return result
}

utilisation

<body>
  <script type="module">
    import {
     
      reactive, effect, computed } from './reactivity/index.js'
    const product = reactive({
     
     
      name: 'iPhone',
      price: 5000,
      count: 3
    })
    let total = computed(() => {
     
     
      return product.price * product.count
    })
    console.log(total.value) // 15000

    product.price = 4000
    console.log(total.value) // 12000

    product.count = 1
    console.log(total.value) // 4000
  </script>
</body>

Remarque: Trigger / track / effct est la fonction sous-jacente, généralement non utilisée. Utiliser calculé au lieu d'effet

Je suppose que tu aimes

Origine blog.csdn.net/jal517486222/article/details/108689672
conseillé
Classement