Maison >interface Web >Voir.js >Quel est le principe de réactivité de Vue3
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 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); }, });
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 :
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); // 依赖更新 }, }); };
let activeEffect; function effect(fn) { const _effect = function reactiveEffect() { activeEffect = _effect; fn(); }; _effect(); }
effect(() => { // effect 的立即执行会访问 state.counter,触发了对象的 get 操作。 document.querySelector("#app").innerHTML = state.counter; });
track
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 副作用函数 ], } ], }, ];
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!