책은 위에서 계속되고, 우리는 이 주제에 대해 계속 논의하고, 나는 여전히 공식 웹사이트의 스크린샷을 여기에 남겨둡니다.
문제 사고
- 분해된 값은 기본 데이터 유형으로 응답성을 잃게 되는데, 참조 데이터 유형이면 응답성을 유지합니까?
- Lost Responsive는
vue
내부적 있습니까?
문제 문의
상대적으로 간단한 장면을 구성하기 위해 먼저 예제를 작성해 보겠습니다.
<script setup>
import { reactive } from "vue";
const state = reactive({
obj: {
name: "zhangsan",
},
});
const handleClick = () => {
const { obj } = state;
obj.name = "lisi";
};
</script>
<template>
<button @click="handleClick">点击切换</button>
<div>{{ state }}</div>
</template>
复制代码
효과는 다음과 같습니다.
아래 코드를 수정해 보겠습니다.
const handleClick = () => {
const { name } = state.obj;
name = "lisi";
};
复制代码
효과는 다음과 같습니다.
위의 비교 결과, deconstructed가 참조 객체 타입일 경우 반응형이며, 기본 데이터 타입을 사용할 경우 반응형이 상실되는 것을 알 수 있다.
소스 코드 분석
최상위 코드에 디버그를 넣고 reactive
메소드 하나 target
를 수신한 다음 읽기 전용인지 판단하고 마지막으로 createReactiveObject
메소드 이 메소드를 입력합니다.
이 방법은 어떤 판단을 하여 먼저 객체인지 아닌지를 판단하고, 그렇지 않다면 값을 반환합니다.
그런 다음 ID __v_raw
가 하고, 그렇다면 반환합니다.
다음 판단 existingProxy
은 proxyMap
Proxy 객체를 데이터 구조에서 직접 빼내어 성능을 향상시키는 방법이라는 것입니다. Proxy 객체는 나중에 proxyMap.set(target, proxy)
동작 , proxyMap
여기서 호출하는 것은 WeakMap
의 인스턴스이다.
그런 다음 아래로 이동하여 반응할 수 있는 개체에 화이트리스트를 추가합니다.Object, Array, Map, Set, WeakMap 및 WeakSet 개체만 반응할 수 있습니다.
마지막으로 Proxy가 수행되며 처음 반응할 때 첫 번째 레이어만 Proxy입니다. Reactive 후 Proxy 객체를 살펴보겠습니다.
이 때 targetType
값 은 1이므로 갑니다 baseHandlers
.이 메소드 createReactiveObject
는 입력 파라미터의 세 번째 파라미터, 즉 mutableHandlers
, Proxy의 공통 메소드를 포함합니다.
createGetter
get
메서드 를 호출한 후 실행되는 함수 입니다. 447행에서 자식이 여전히 객체인 경우 reactive
딥 프록시를 수행하기 위해 재귀적으로 호출한다는 것을 발견했습니다. 이 시점에서 소스 코드가 손실된 응답, 즉 손실된 Reactivity는 Vue가 아니라 Proxy 개체 자체에 있습니다.
간단한 구현
const obj = {
count: 1
};
const proxy = new Proxy(obj, {
get(target, key) {
console.log("get");
return target[key]
},
set(target, key, value) {
console.log("set");
target[key] = value
return true;
}
});
console.log(proxy.count);
复制代码
값을 읽으려고 하면 get
메서드 되고 값이 설정되면 set
메서드가 호출됩니다. let { count } = proxy; count = 2
구조화 및 재할당이 set
메서드 호출을 트리거하지 않는 경우. 그런 다음 Destructuring이 참조 데이터 유형인 경우 이제 위의 코드를 변경해 보겠습니다.
const obj = {
counter: {
count: 1
}
};
const reactive = (target) => {
return new Proxy(obj, {
get(target, key) {
console.log("get");
if (typeof target[key] === 'object') {
return reactive(target[key]);
}
return target[key]
},
set(target, key, value) {
console.log("set");
target[key] = value
return true;
}
});
}
let {
counter
} = reactive(obj);
counter.count = 2
复制代码
이 때, 위의 결론을 확인하는 get
방법과 set
방법 을 모두 호출합니다.