Vue3의 반응성 원리는 무엇입니까?

王林
풀어 주다: 2023-05-24 17:55:23
앞으로
1297명이 탐색했습니다.

Proxy

Proxy의 핵심 API는 Vue3의 반응 원리에 의존합니다. Proxy는 일부 객체 작업을 가로채는 데 사용될 수 있습니다.

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 개체의 속성 액세스, 속성 할당, 연산자 및 삭제 작업을 프록시하고 console.log 출력을 수행합니다.

Reflect

Reflect는 특정 작업을 하이재킹할 때 이러한 작업을 다시 반영해야 하는 경우 프록시와 함께 사용되는 API입니다.

객체의 작업을 가로채기 때문에 이러한 작업의 기능은 손실됩니다. 예를 들어 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>
로그인 후 복사

반응형 객체 상태를 생성하기 위해 반응형을 사용하고 부작용 함수를 허용하는 효과 메서드를 호출했습니다. 효과가 실행되면 즉시 부작용 함수가 호출되고 2초 동안 #app.innerHTML에 state.counter가 할당됩니다. 마지막으로 state.counter += 1. 이때 Effect의 Side Effect 기능이 다시 실행되어 페이지가 2가 됩니다. 내부 실행 과정은 대략 아래 그림과 같습니다.

Vue3의 반응성 원리는 무엇입니까?

    Reactive() 호출은 프록시 객체를 반환하고 객체의 get 및 set 작업을 하이재킹합니다. effect() 메서드가 호출되면 state.counter 속성에 액세스하여 프록시의 get 작업을 트리거합니다.
  • get 메서드는 track()을 호출하여 종속성을 수집합니다. 객체(상태), 속성(카운터) 및 효과 부작용 함수 간의 종속 관계를 설정합니다.
  • set 메서드는 Trigger()를 호출합니다. 종속성을 업데이트하려면 객체(상태)와 속성(카운터)을 통해 해당 효과 부작용 함수를 찾은 다음 다시 실행합니다.
  • reactive
  • reactive는 다음 프록시 객체를 반환합니다.

    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 변수를 정의합니다. effect는 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);
  }
}
로그인 후 복사

실행이 완료되면 다음과 같은 데이터 구조를 얻게 됩니다.

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

참고: 언제 effect를 호출하면 현재 부작용 함수를 전역 activeEffect에 할당하므로 이때 해당 종속성을 올바르게 연결할 수 있습니다.

trigger

state.counter에 값을 할당하면 프록시 객체의 설정 작업이 트리거되어 트리거 메서드가 호출됩니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:yisu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿