ホームページ >ウェブフロントエンド >Vue.js >Vue3 の応答原理とは何ですか

Vue3 の応答原理とは何ですか

王林
王林転載
2023-05-24 17:55:231343ブラウズ

プロキシ

プロキシのコア API は、Vue3 の応答原理に依存しています。プロキシは、一部のオブジェクト操作をインターセプトするために使用できます。

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

上記の例に示すように、Proxy を使用して、Obj オブジェクトのプロパティ アクセス、プロパティの割り当て、in 演算子、および削除操作をプロキシし、console.log 出力を実行します。

Reflect

Reflect は Proxy と組み合わせて使用​​される API です。特定の操作をハイジャックしたときに、これらの操作を反映させる必要がある場合は、この API を Reflect する必要があります。

オブジェクトの操作をインターセプトしたため、これらの操作の機能は失われます。たとえば、属性 p.a にアクセスすると、a 属性の値が取得されるはずですが、この時点では結果は得られません。インターセプト前に関数を使用したい場合は、Reflect を使用して反射する必要があります。

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);
  },
});

例を示します

この例を使用して、次のテキスト全体で Vue3 の応答性の原理を説明します。

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

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

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

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

reactive を使用してリアクティブ オブジェクトの状態を作成し、副作用関数を受け入れるエフェクト メソッドを呼び出しました。エフェクトを実行すると、すぐに副作用関数が呼び出され、state.counter が #app.innerHTML に割り当てられます。 ; 2 秒後、state.counter = 1. このとき、effect の副作用関数が再実行され、ページは 2 になります。以下の図:

Vue3 の応答原理とは何ですか

    reactive() を呼び出して Proxy プロキシ オブジェクトを返し、オブジェクトの get および set 操作をハイジャックします
  • effect() メソッドを呼び出すと、プロパティ state.counter がアクセスされ、プロキシの get オペレーションがトリガーされます。
  • get メソッドは track() を呼び出して依存関係を収集し、オブジェクト (状態)、属性 (カウンター)、および効果の副作用関数間の依存関係を確立します。
  • set メソッドは、trigger() を呼び出して依存関係を更新します。オブジェクト (状態) と属性 (カウンター) を通じて対応する効果副作用関数を見つけて、それを再実行します。
  • reactive

reactive は次の Proxy オブジェクトを返します。

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();
}

を指すグローバル activeEffect 変数を定義します。現在実行中のエフェクトの副作用関数を更新し、それを更新し続けます。エフェクトは fn の内部副作用関数を作成し、すぐに実行します。このとき、オブジェクトの get 操作がトリガーされ、track() メソッドが呼び出されます。

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

track

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);
  }
}

実行が完了すると、A が得られますデータ構造は次のとおりです。

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

注:effect を呼び出すと、現在の副作用関数がグローバル activeEffect に割り当てられるため、この時点でその依存関係を正しく関連付けることができます。

trigger

state.counter に値を割り当てると、プロキシ オブジェクトの set 操作がトリガーされ、トリガー メソッド

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());
}
が呼び出されます。

以上がVue3 の応答原理とは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。