Maison  >  Article  >  interface Web  >  Quel est le principe de réactivité de Vue3

Quel est le principe de réactivité de Vue3

王林
王林avant
2023-05-24 17:55:231291parcourir

Proxy

L'API principale de Proxy dépend du principe réactif de Vue3. Proxy peut être utilisé pour intercepter certaines opérations sur les objets.

const obj = { a: 1 };
const p = new Proxy(obj, {
  get(target, property, receiver) {
    console.log("get");
    return Reflect.get(target, property, receiver);
  },
  set(target, property, value, receiver) {
    console.log("set");
    return Reflect.set(target, property, receiver);
  },
  has(target, prop) {
    console.log("has");
    return Reflect.has(target, prop);
  },
  deleteProperty(target, prop) {
    console.log("deleteProperty");
    return Reflect.deleteProperty(target, prop);
  },
});

p.a; // 输出 --> get
p.a = 2; // 输出 --> set
"a" in p; // 输出 --> has
delete p.a; // 输出 --> deleteProperty

Dans l'exemple ci-dessus, nous utilisons Proxy pour proxy les opérations d'accès aux propriétés, d'affectation des propriétés, d'opérateur in et de suppression de l'objet Obj, et effectuons la sortie console.log.

Reflect

Reflect est une API utilisée conjointement avec Proxy. Lorsque nous détournons certaines opérations, si nous devons refléter ces opérations, nous devons refléter cette API.

Depuis que nous avons intercepté les opérations de l'objet, les fonctions de ces opérations sont perdues. Par exemple, accéder à l'attribut p.a devrait obtenir la valeur de l'attribut a, mais il n'y aura aucun résultat pour le moment. avoir la fonction avant la fonction d'interception, nous devons alors utiliser Reflect pour la refléter.

const obj = { a: 1 };
const p = new Proxy(obj, {
  get(target, property, receiver) {
    console.log("get");
    return Reflect.get(target, property, receiver);
  },
  set(target, property, value, receiver) {
    console.log("set");
    return Reflect.set(target, property, receiver);
  },
  has(target, prop) {
    console.log("has");
    return Reflect.has(target, prop);
  },
  deleteProperty(target, prop) {
    console.log("deleteProperty");
    return Reflect.deleteProperty(target, prop);
  },
});

Donnez un exemple

Nous utiliserons cet exemple pour décrire le principe de réactivité de Vue3 tout au long du texte suivant.

<div id="app"></div>

<script>
  // 创建一个响应式对象
  const state = reactive({ counter: 1 });

  // 立即运行一个函数,当响应式对象的属性发生改变时重新执行。
  effect(() => {
    document.querySelector("#app").innerHTML = state.counter;
  });

  // 2s 后视图更新
  setTimeout(() => {
    state.counter += 1;
  }, 2000);
</script>

Nous avons utilisé réactif pour créer un état d'objet réactif et avons appelé la méthode d'effet, qui accepte une fonction d'effet secondaire, appellera immédiatement la fonction d'effet secondaire et attribuera state.counter à #app.innerHTML deux secondes ; Enfin, state.counter += 1. À ce moment, la fonction d'effet secondaire de l'effet sera réexécutée et la page deviendra 2. Le processus d'exécution interne est à peu près tel qu'illustré dans la figure ci-dessous :

Quel est le principe de réactivité de Vue3

    Call reactive() Renvoie un objet Proxy et détourne les opérations get et set de l'objet. Lorsque la méthode effect() est appelée, la propriété state.counter sera accédée, ce qui déclenchera l'opération get du proxy. La méthode
  • get appellera track() pour collecter les dépendances ; établit une relation de dépendance entre un objet (état), un attribut (compteur) et la fonction d'effet secondaire ; la méthode
  • set appellera trigger() ; pour mettre à jour les dépendances ; via l'objet (état) et l'attribut (coutner), recherchez la fonction d'effet secondaire correspondante, puis exécutez-la à nouveau.
  • reactive
  • reactive renverra l'objet proxy suivant

    const reactive = (target) => {
      return new Proxy(target, {
        get(target, key, receiver) {
          const res = Reflect.get(target, key, receiver);
    
          track(target, key); // 收集依赖
    
          if (isObject(res)) {
            // 如果当前获取的属性值是一个对象,则继续将为此对象创建 Proxy 代理
            return reactive(res);
          }
    
          return res;
        },
    
        set(target, key, value, receiver) {
          Reflect.set(target, key, value, receiver);
          trigger(target, key); // 依赖更新
        },
      });
    };
  • effect
let activeEffect;
function effect(fn) {
  const _effect = function reactiveEffect() {
    activeEffect = _effect;
    fn();
  };

  _effect();
}

Définissez une variable globale activeEffect, qui pointe vers la fonction d'effet secondaire d'effet en cours d'exécution et la maintient à jour. effect crée une fonction d'effet secondaire interne pour fn puis l'exécute immédiatement. À ce moment, l'opération get de l'objet sera déclenchée et la méthode track() sera appelée.

effect(() => {
  // effect 的立即执行会访问 state.counter,触发了对象的 get 操作。
  document.querySelector("#app").innerHTML = state.counter;
});

track

track créera une dépendance d'un objet (état) => attribut (compteur) => effet

const targetMap = new WeakMap();
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()));
  }

  if (!dep.has(activeEffect)) {
    dep.add(activeEffect);
  }
}

Une fois l'exécution terminée, nous obtiendrons la structure de données suivante :

[ // map 集合
  {
    key: {counter: 1} // state 对象,
    value: [ // map 集合
      {
        key: "counter",
        value: [ // set
          function reactiveEffect() {} // effect 副作用函数
        ],
      }
    ],
  },
];

Remarque : Quand Quand nous appelons effet, nous attribuerons la fonction d'effet secondaire actuelle à l'activeEffect global, afin que nous puissions associer correctement ses dépendances à ce moment-là.

trigger

Lorsque nous attribuons une valeur à state.counter, l'opération définie de l'objet proxy sera déclenchée, appelant ainsi la méthode de déclenchement

setTimeout(() => {
  // 给 counter 属性赋值会触发 set 操作
  state.counter += 1;
}, 2000);
function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;

  const effects = depsMap.get(key);
  effects && effects.forEach((effect) => effect());
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer