모바일 이해의 Vue3 Reactivity의 구조적 후편
전편에서는 이미 targetMap을 통해 여러 객체를 관리할 수 있게 됐다.
후편에서 수동 호출
track,trigger 함수를 자동으로 호출합니다.track(product, "quantity"); // ←自動で呼ばれて欲しい
product.quantity = 5;
trigger(product, "quantity"); // ←自動で呼ばれて欲しい
즉, 속성의 get/set을 차단할 수 있다면 좋겠다.
Reflect
이른바 Reflect
JavaScript 작업에 개입할 수 있는 내장 객체를 제공합니다.
MDN에서
에서 target에서 지정한 대상의 함수를 호출하거나 속성을 가져올 수 있습니다.
그중 이번에는 Reflect.get을 사용합니다.
Reflect.get을 사용하면 대상에서 속성을 얻을 수 있습니다.
(receiver는 뒤에 설명합니다.)
Reflect.get(product, 'quantity', receiver) // => 3
Proxy
Proxy 다음과 같이 대상을 싸서 Proxy(대리인)가 대상에 접근할 수 있도록 합니다.
예를 들어 Proxy의 두 번째 매개 변수에 처리 프로그램을 전달하면 속성에 접근할 때 get 함수를 차단할 수 있습니다.
추가 Reflectget과 조합해서 사용하면 다음과 같습니다.
let product = { price: 5, quantity: 2 };
let proxiedProduct = new Proxy(product, {
  get(target, key) {
    console.log("Get key", key);
    return target[key];
  }
});
// Get key quantity 
// 2
console.log(proxiedProduct.quantity);
get과 마찬가지로 set도 다음과 같이 정의할 수 있습니다.
let product = { price: 5, quantity: 2 };
let proxiedProduct = new Proxy(product, {
  get(target, key, receiver) {
    console.log("Get key", key);
    return Reflect.get(target, key, receiver);
  }
});
console.log(proxiedProduct.quantity);
reactive 정의
리플렉스와 프록시를 파악한 끝에 드디어 실장에 들어갔다.
매개변수 "reactive"로 전달된 데이터가 Proxy화되어 반환되는 함수를 정의합니다.
let product = { price: 5, quantity: 2 };
let proxiedProduct = new Proxy(product, {
  get(target, key, receiver) {
    console.log("Get key", key);
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    console.log("Set called", key, value);
    return Reflect.set(target, key, value, receiver);
  }
});
proxiedProduct.quantity = 10;
console.log(proxiedProduct.quantity);
즉, 속성의 get/set을 차단할 수 있다면 좋겠다.
그리고 트랙과 trigger를 각각 실행합니다.
속성이 get에 호출되었을 때 트랙 사용하기
속성이 설정되었을 때 trigger를 호출합니다
function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      console.log("Get key", key);
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      console.log("Set called", key, value);
      return Reflect.set(target, key, value, receiver);
    }
  };
  return new Proxy(target, handler);
}
let product = { price: 5, quantity: 2 };
let proxiedProduct = reactive(product);
나는 당신이 직감적인 견해에 주의를 기울였다고 생각한다. 이것은 Composition API의 reactive에 해당한다.
드디어 완성됐습니다.🎉
그러면 마지막으로 정의한reactive 함수가 제대로 실행되었는지 확인하십시오.
앞부분을 포함하는 코드는 전체적으로 다음과 같다.
코드 확장
function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      let result = Reflect.get(target, key, receiver);
      // getされたらtrackを呼び出す
      track(target, key);
      return result;
    },
    set(target, key, value, receiver) {
      let oldValue = target[key];
      let result = Reflect.set(target, key, value, receiver);
      // 値が変更されたらtriggerを呼び出す
      if (result && oldValue !== value) {
        trigger(target, key);
      }
      return result;
    }
  };
  return new Proxy(target, handler);
}
요점
먼저 totalEffect()를 초기화할 때 호출합니다.
프로젝트, Quantity의 변경 사항을 추적하기 위해 내부에서 트랙을 호출합니다.
// targetMapを定義
const targetMap = new WeakMap();
function track(target, key, effect) {
  // targetMapからdepsMapを取得
  let depsMap = targetMap.get(target);
  // depsMapがなければ作成する
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  // depを取得
  let dep = depsMap.get(key);
  // depが存在しなければ作成する
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(effect);
}
function trigger(target, key) {
  // targetMapからdepsMapを取得
  const depsMap = targetMap.get(target);
  // なければリターン
  if (!depsMap) {
    return;
  }
  let dep = depsMap.get(key);
  if (dep) {
    dep.forEach((effect) => effect());
  }
}
function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      let result = Reflect.get(target, key, receiver);
      track(target, key, totalEffect);
      return result;
    },
    set(target, key, value, receiver) {
      let oldValue = Reflect.get(target, key, receiver);
      let result = Reflect.set(target, key, value, receiver);
      if (result && oldValue !== value) {
        trigger(target, key);
      }
      return result;
    }
  };
  return new Proxy(target, handler);
}
let product = reactive({ price: 200, quantity: 3 });
let total = 0;
const totalEffect = () => {
  total = product.price * product.quantity;
};
// 初期化
// effect内でpriceとquantityがgetされることで
// track(product, 'price')
// track(procut, 'quantity')
// がコールされる
totalEffect()
// quantityにsetされることで
// trigger(product, 'quantity')がコールされ
// effectが再計算されるがコールされ、totalが更新される。
product.quantity = 4;
console.log(total); // => 800
// 初期化
// effect内でpriceとquantityがgetされることで
// track(product, 'price')
// track(procut, 'quantity')
// がコールされる
totalEffect()
track,trigger 자동 호출, 설정값만 있으면 토탈을 업데이트합니다🎉어때요?
프레임의 인터페이스를 이용하는 것 뿐만 아니라 이번처럼 내부 구조를 이해함으로써 디버깅을 하고 디자인을 배우며 프로그램 디자인을 깊이 있게 이해하면 프로그래밍의 즐거움을 누릴 수 있지 않겠는가.
[추기] 레프에 대해서.
reactive가 있다면 많은 사람들이 ref라고 생각할 것 같아서 가볍게 건드려보세요.
예를 들어 다음과 같은 total이saleProice의 다른 effect의 결과로 대입된 값에 의존하는 상황을 고려한다.
// quantityにsetされることで
// trigger(product, 'quantity')がコールされ
// effectが再計算されるがコールされ、totalが更新される。
product.quantity = 4;
console.log(total); // => 800
let product = reactive({ price: 5, quantity: 2 })
let salePrice = 0
let total = 0
effect(() => {
  // totalはsalePriceに依存する
  total = salePrice * product.quantity
})
effect(() => {
  salePrice = product.price * 0.9
})
// salePriceには変更されるが、salePriceに依存するtotalの値は変更されない
product.price = 10
console.log(
  `total (should be 18) = ${total} salePrice (should be 9) = ${salePrice}`
  // total (should be 18) = 0 salePrice (should be 9) = 9
)
이른바
property만value의reactive 대상으로
따라서 단일 값을 reactive로 직접 사용할 수 있습니다.
이번 예에서는 다음과 같은 방법을 통해 반영해야 한다.
// salePriceには変更されるが、salePriceに依存するtotalの値は変更されない
product.price = 10
console.log(
  `total (should be 18) = ${total} salePrice (should be 9) = ${salePrice}`
  // totalが0更新されず0のままになっている。
  // total (should be 18) = 0 salePrice (should be 9) = 9
)
ref 설치
ref를 실현하는 두 가지 방법이 있어요.
첫 번째 방법은 간단하게 리얼리티로 싸는 것이다.
let product = reactive({ price: 5, quantity: 2 })
let salePrice = ref(0) // refの使用
let total = 0
// effectの中では.valueを使うようにする
effect(() => {
  total = salePrice.value * product.quantity
})
effect(() => {
  salePrice.value = product.price * 0.9
})
ObjectAccess 정보
그 구현을 보기 전에 먼저 ObjectAccess를 실제로 이해해야 합니다.
이것은 별명
JavaScript computed properties(Vue의 컴퓨터property와 다른 것)으로 다음과 같은 정의get/set로 컴퓨터property를 정의할 수 있습니다.function ref(initialValue){
  return reactive({value: initialValue})
}
let user = {
  firstName: 'Gregg',
  lastName: 'Pollack',
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  },
  set fullName(value) {
    [this.firstName, this.lastName] = value.split(' ')
  },
}
console.log(`Name is ${user.fullName}`)
user.fullName = 'Adam Jahr'
console.log(`Name is ${user.fullName}`)
Reference
이 문제에 관하여(모바일 이해의 Vue3 Reactivity의 구조적 후편), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/kazuwombat/articles/3cc9b504dd5999텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)