ref 도입은 프록시가 원래 값을 직접 프록시할 수 없는 문제를 해결하기 위한 것입니다. 먼저 ref의 사용법을 살펴보겠습니다.
const name = ref('小黑子')
ref는 어떻게 구현되나요? 실제로는 원래 값을 객체로 "래핑"하는 것입니다. ref의 구현을 살펴보겠습니다.
function ref(val){ // 使用对象包裹原始值 const wrapper = { value:val } // 利用 reactive 将对象变成响应式数据 return reactive(wrapper) }
ref 구현은 매우 간단합니다.
ref는 원래 값에 대한 응답으로 주로 다음 두 가지 작업을 수행합니다.
1 개체를 사용하여 원래 값을 래핑합니다.
2. 반응형을 사용하여 패키지 개체를 반응형 데이터로 전환합니다.
ref를 사용하여 반응형 객체를 생성하는데, 객체가 일반 객체인지 ref 객체인지 어떻게 구별하나요? 그래서 isref가 나타납니다.
사용법을 살펴보겠습니다.
const name = ref('cj') console.log(isRef(name)); // true
그럼 구현 원리는 무엇인가요? 주요 구현은 여전히 ref API 내에 있습니다. 특정 구현 코드를 살펴보겠습니다.
function ref(val){ const wrapper = { value:val } Object.defineProperty(warpper,'__v_isRef',{ value:true }) return reactive(wrapper) }
ref 내의 패키지 개체에 열거할 수 없고 쓸 수 없는 속성을 추가하고 값은 true입니다. . 이런 식으로 우리는 속성을 확인하여 그것이 심판인지 결정할 수 있습니다.
function isRef(val) { return val.__v_isRef ?? false }
응답 손실이란 무엇인가요? 응답 손실은 응답 데이터에 응답하지 않음을 의미합니다. 아래 코드를 살펴보겠습니다.
const obj = reactive({foo:1,bar:2}) const {foo,bar} = obj obj.foo++ // foo不会改变,还是 1
위 obj가 응답을 잃어서 다시 렌더링이 실행되지 않습니다. 왜 그럴까요? 실제로 구조 할당을 사용하기 때문에 확장 연산자도 이를 무효화합니다.
const obj = reactive({foo:1,bar:2}) const newObj = {...obj} obj.foo++ // newObj.foo不会改变,还是 1
이는 더 이상 원본 응답 데이터가 아니며 당연히 응답 기능이 없는 새 데이터를 재정의하는 것과 같습니다.
toRef는 응답 손실 문제를 해결하는 것입니다. 구현을 살펴보겠습니다.
function toRef(obj,key) { const wrapper = { get value() { return obj[key] }, set value(val) { obj[key] = val } } Object.defineProperty(wrapper,'__v_isRef',{ value:true }) return wrapper }
두 개의 매개변수를 전달합니다. 첫 번째는 반응형 데이터이고 두 번째는 obj의 키입니다.
첫 번째 부분은 객체를 설정하고 선언하는 것입니다. 객체는 먼저 값 속성의 가져오기를 설정합니다. toRef 값에 액세스하면 수신된 응답 데이터에 해당하는 속성 값이 반환됩니다. value 속성이 사용됩니다. toRef 값이 설정되면 새 값 세트가 응답 데이터에 해당하는 속성 값을 업데이트하는 데 사용됩니다. 즉, toRef에서 반환된 개체는 여전히 사용되는 반응형 데이터입니다.
두 번째 부분은 반환된 데이터를 참조 데이터로 설정하는 데 사용됩니다. toRef가 반환하는 데이터는 ref 데이터와 유사하므로 통일성을 위해 직접 ref 데이터로 간주합니다.
세 번째 부분은 응답 데이터에 대응하여 선언된 속성 개체를 반환하는 것입니다.
이런 방식으로 toRef는 응답 손실 문제를 해결합니다.
toRefs를 추가하는 것은 전체 반응형 개체를 분해하여 반응형으로 만드는 것입니다. 구현 코드는 다음과 같습니다.
function toRefs() { const ret = {} for (const key in obj) { ret[key] = toRef(obj,key) } return ret }
for 루프를 사용하여 속성을 하나씩 변환합니다. 이제 사용법을 살펴보겠습니다.
const obj = reactive({foo:1,bar:2}) const {foo,bar} = toRefs(obj) obj.foo++ // foo.value变为2了
속성이 원본 값이 아닌 경우 해체 후에도 여전히 응답할 수 있습니다
const obj = reactive({foo:{age:18},bar:2}) const {foo,bar} = obj obj.foo.age++ // foo.age变为2了 obj.bar++ // bar没有改变,还是1
왜일까요? 그 이유는 실제로 매우 간단합니다. 원본이 아닌 값에 참조 주소가 할당되기 때문입니다. 이는 구조 해제된 변수가 실제로 여전히 원본 응답 데이터의 속성을 가리킨다는 의미입니다. 원래 값은 간단한 할당이므로 응답하지 않습니다.
reactive 响应数据重新赋值后不再响应,ref 响应数据赋值后依然响应 let obj1 = reactive({foo:1,bar:2}) let obj2 = ref({foo:1,bar:2}) // 假如 obj1 与 obj2 直接展示在页面上 obj1 = {boo:2,far:3} // 页面 obj1 还是 {foo:1,bar:2} obj2.value = {boo:2,far:3} // 页面 obj2 变为 {boo:2,far:3} 了
이유는 무엇인가요? Reactive 재할당 응답이 손실됩니다. 즉, 새로운 객체가 재할당되며 자연스럽게 일반 데이터가 되어 더 이상 응답하지 않게 됩니다. 그리고 ref가 내부적으로 설정되어 있기 때문에 ref는 여전히 응답할 수 있습니다. 코드는 다음과 같습니다.
function ref(val){ const wrapper = { value:val set value(val) { // isObject 这里代表判断是否是非原始值的一个方法 value = isObject(val) === 'Object' ? reactive(val) : val } } Object.defineProperty(warpper,'__v_isRef',{ value:true }) return reactive(wrapper) }
사실 ref는 set에 설정된 새 값이 원본 값이 아닌지 확인하고, 그렇다면 반응형 데이터를 호출하여 반응형 데이터로 바꾸는 것으로 이해합니다.
ref 반응형 데이터를 사용할 때 우리는 항상 값을 얻기 위해 .value가 필요하다고 느끼게 되며, 이는 사용자의 정신적 부담을 증가시킵니다.
.value를 사용하는 대신 값에 직접 액세스할 수 있나요?
이렇게 사용하면 특정 데이터가 ref 데이터인지, value 속성을 통해 값을 얻어야 하는지 걱정할 필요가 없습니다.
여기서 unref가 작동합니다. unref는 ref를 자동으로 제거하는 기능을 구현합니다. 자동 ref 제거는 읽은 속성이 ref인 경우 해당 ref에 해당하는 value 속성 값이 직접 반환됨을 의미합니다.
unref의 구현을 살펴보겠습니다.
function unref(target) { return new Proxy(target,{ get(target,key,receiver) { const value = Reflect.get(target,key,receiver) return value.__v_isRef ? value.value : value }, set(target,key,newValue,receiver) { const value = target[key] if (value.__v_isRef) { value.value = newValue return true } return Reflect.set(target,key,newValue,receiver) } }) }
unref가 내부적으로 대상 객체를 프록시하기 위해 프록시를 사용하고, 객체를 매개변수로 받고, 객체의 프록시 객체를 반환한다는 것을 발견했습니다. unref 데이터에 액세스하면 get catcher가 트리거되고 catcher는 들어오는 객체가 ref 객체인지 내부적으로 확인하고, 그렇다면 ref의 .value 값을 직접 반환합니다. 그렇지 않은 경우 프록시 개체가 직접 반환됩니다.
unref에 의해 반환된 프록시 객체의 값을 설정하면 set Capturer가 트리거됩니다. 프록시 객체가 ref이면 설정해야 하는 새 값이 .value에 할당됩니다. 그렇지 않은 경우 할당 프로세스가 직접 수행됩니다. .
ref를 사용하여 반응형 데이터를 생성하고 이를 템플릿에 표시한 후 .value를 사용하는 것은 어떨까요?
{{ name }}
其实原因很简单,在组件 setup 中声明的 ref 响应式数据会传递给 unref 函数进行处理。所以在模板中访问 ref 的值,无需通过 value 属性来访问。
我们使用的 reactive 其实也是有 自动脱 ref 功能的,看一下下方例子:
const count = ref(0) const obj = reactive({conut}) obj.count // 0
我们可以看见 obj.count 是一个 ref 响应式数据。在 count 外层包裹一层对象,再传递给 reactive 后,再访问 obj.count 时就不需要再通过 value 属性访问值了。
也正是因为 reactive 内部也同样实现了自动脱 ref 的能力。
위 내용은 vue3 원래 값 응답 솔루션 및 응답 손실 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!