>  기사  >  웹 프론트엔드  >  Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2023-01-09 18:32:552174검색

Vue2의 DefineProperty로 구현된 데이터 응답성에 비해 Vue3는 데이터 응답 처리에서 더 명확한 업무 분담을 가지고 있으며, 결합된 API에서 개발자에게 노출되는 ref 및 반응성이라는 두 가지 기능을 통해 데이터를 패키징하여 데이터 응답성을 달성합니다. 차이점은 무엇입니까? 예시를 통해 함께 배워보아요!

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

ref: 기본 데이터 유형과 참조 데이터 유형을 정의하는 응답성. 즉, ref(value), 이 값 유형은 기본 데이터 유형일 수도 있고 참조 데이터 유형일 수도 있지만, js에서 사용할 때는 property.value 형식으로 사용해야 합니다. 템플릿 통화 데이터에서 직접 사용할 수 있습니다. 定义基本数据类型、引用数据类型的响应式。也就是说ref(value),这个value类型可以是基本数据类型,也可以是引用数据类型,但是在js中使用时必须以属性.value格式使用,在template中可以直接调用数据。

<template>
  <div>
    <div><button @click="changeValue">修改</button></div>
    <div>
      <p>当前strRef:{{ strRef }}</p>
      <p>当前objRef:姓名:{{ objRef.name }} 爱好:{{ objRef.hobboy }}</p>
      <p>当前arrRef:{{ arrRef }}</p>
    </div>
  </div>
</template>
<script>
import { defineComponent, ref, shallowRef } from &#39;vue&#39;
export default defineComponent({
  setup () {
    const strRef = ref(&#39;sapper&#39;);// 基本数据类型
    const arrRef = ref([1, 3, 2]);// 数组类型
    const objRef = ref({  // 对象类型
      name: &#39;sapper&#39;,
      hobboy: [&#39;吉他&#39;, &#39;原神&#39;]
    })
    const changeValue = () => {
      strRef.value = &#39;工兵&#39;;
      arrRef.value[1] = 4;
      objRef.value.hobboy[1] = &#39;滑冰&#39;;
    }
    return {strRef,objRef,arrRef,changeValue}
  }
})
</script>

reactive定义引用类型数据的响应式,不支持基本数据类型,如果需要写基本数据类型只能是放在对象中,也就是说reactive(value),这个value类型必须是引用类型。【相关推荐:vuejs视频教程web前端开发

<template>
  <div>
    <div><button @click="changeValue">修改</button></div>
    <div>
      <div>当前objReactive:
        <br/>
        姓名:{{ objReactive.name }}<br/> 
        爱好:{{ objReactive.hobboy }}
      </div>
      <div>当前arrReactive:{{ arrReactive }}</div>
    </div>
  </div>
</template>
<script>
import { defineComponent, reactive } from &#39;vue&#39;
export default defineComponent({
  setup () {
    const arrReactive = reactive([1, 3, 2]);// 数组类型
    const objReactive = reactive({  // 对象类型
      name: &#39;sapper&#39;,
      hobboy: [&#39;吉他&#39;, &#39;原神&#39;]
    })
    const changeValue = () => {
      arrReactive[1] = 4;
      objReactive.name = &#39;工兵&#39;;
      objReactive.hobboy[1] = &#39;滑冰&#39;;
    }
    return {objReactive,arrReactive,changeValue}
  }
})
</script>

从上面两个例子中我们可以看出不管什么类型数据,ref都需要以.value来调用ref定义的数据,对于引用数据类型来看,我们可以看出代码不美观,所以一般对于引用类型数据,都推荐使用reactive来定义对于基本数据类型,可以使用ref也可以使用reactive来定义。既然到了这里我们都了解了ref和reactive的运用区别了,那么我们继续来一起探讨一下它们的响应原理又有什么区别?

揭秘ref

从上面的例子,我们先打印看一下基本数据类型(strRef)、引用数据类型(arrRef、ObjRef)的ref内部封装结构是什么样的?如下三图所示

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명从上面图片可以看出,不管是什么类型的数据,对于ref封装数据都是一个RefImpl对象reference implement的简写,是引用实现的意思,每个RefImpl对象都有6个属性:

  • dep:是一个Set类型的数据,用来存储当前的ref值收集的依赖。

  • _ v _ isRef :标记位,只要被ref定义了,都会标识当前数据为一个Ref,也就是它的值标记为true。

  • _ v _ isShallow:判断是否是shallowRef定义的数据。

    与ref不同的是,当使用shallowRef为引用类型创建响应性时,修改深层属性,不具备响应性。只有对.value的引用时才触发。

    const state = shallowRef({ count: 1 })
    // 不会触发更改
    state.value.count = 2
    // 会触发更改
    state.value = { count: 2 }
  • _ rawValue:用于保存当前ref值对应的原始值,如果传递的参数是对象,它就是用于保存转化前的原始值,否则_ value与_ rawValue相同。

  • _ value:用于保存ref当前值,如果传递的参数是对象,它就是用于保存经过reactive函数转化后的值,否则_ value与_ rawValue相同。从上面例子我们可以发现,对于引用类型的数据,它的值就是一个proxy对象,这其实就是reactive封装数据后对象(后面会说)。我们先看一下下图,发现_ rawValue就是没有做响应性处理的原始值,在看看_ value是一个proxy对象就是做了reactive响应处理的值。

    _ rawValue_ value就是为了区分引用类型数据是否做响应式处理。

Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

  • value:保存的是当前的值。

既然我们清楚了ref给数据封装了什么属性,接下来开始探讨源码究竟给怎么给上面6个属性进行赋值的:

  • ref函数:Vue3向开发者暴露的是ref函数,其实它就是封装了一个createRef函数。

    export function ref(value?: unknown) {
      return createRef(value, false)
    }
  • createRef函数:有两个参数,一个是要做响应处理的数据,一个是判断数据是否为shallowRef定义的数据

    function createRef(rawValue: unknown, shallow: boolean) {
      if (isRef(rawValue)) {
        return rawValue
      }
      return new RefImpl(rawValue, shallow)
    }

    🎜reactive🎜: 기본 데이터 유형을 지원하지 않는 참조 유형 데이터의 응답을 정의합니다. 기본 데이터 유형을 작성해야 하는 경우 객체에만 넣을 수 있습니다. , 반응성(값), 이 값 유형은 참조 유형이어야 합니다. [관련 권장사항: vuejs 비디오 튜토리얼, 웹 프론트엔드 개발]🎜
    const arrReactive = reactive([1, 3, 2]);// 数组类型
    const objReactive = reactive({  // 对象类型
      name: &#39;sapper&#39;,
      hobboy: [&#39;吉他&#39;, &#39;原神&#39;]
    })
    const changeValue = () => {
      arrReactive[1] = 4;
      objReactive.name = &#39;工兵&#39;;
      objReactive.hobboy[1] = &#39;滑冰&#39;;
      console.log(&#39;arrReactive&#39;,arrReactive);
      console.log(&#39;objReactive&#39;,objReactive);
    }
    🎜위의 두 가지 예에서 알 수 있는 것은 어떤 유형 데이터와 ref가 ref로 정의된 데이터를 호출하려면 .value를 사용해야 합니다. 참조 데이터 유형의 경우 코드가 아름답지 않다는 것을 알 수 있으므로 일반적으로 🎜참조 유형 데이터의 경우, 🎜기본 데이터 유형의 경우 ref 또는 반응형을 사용하여 🎜을 정의할 수 있습니다. 이제 우리 모두 여기서 ref와 반응 사용의 차이점을 이해했으므로 응답 원리의 차이점을 계속해서 살펴보겠습니다. 🎜

    🎜Revealing ref🎜

    🎜위의 예에서 먼저 기본 데이터 유형(strRef)과 참조 데이터 유형(arrRef)의 참조 내부를 인쇄하고 살펴봅니다. , ObjRef) 포장 구조는 어떻게 생겼나요? 다음 세 장의 사진과 같이🎜🎜Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명🎜🎜Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명🎜 🎜Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명에서 위 그림을 보면 어떤 데이터 유형이든 ref 캡슐화된 데이터는 🎜RefImpl 객체🎜라는 것을 알 수 있습니다. referenceimplement의 약어는 각 RefImpl 객체가 6개라는 의미입니다. 속성: 🎜
    • 🎜🎜dep🎜: 현재 참조 값으로 수집된 종속성을 저장하는 데 사용되는 Set 유형 데이터입니다. 🎜
    • 🎜🎜_ v _ isRef🎜: 표시 비트. ref로 정의된 한 현재 데이터를 Ref로 표시합니다. 즉, 해당 값이 true로 표시됩니다. 🎜
    • 🎜🎜_ v _ isShallow🎜:shallowRef로 정의된 데이터인지 확인합니다. 🎜
      🎜ref와는 달리,shallowRef를 사용하여 참조 유형에 대한 응답성을 생성하면 깊은 속성이 수정되고 응답성이 없습니다. .value에 대한 참조에 대해서만 실행됩니다. 🎜
      const houseOwner = {home:&#39;房源&#39;,price:1200,type:&#39;一房一厅&#39;};
      const proxyOwner = new Proxy(houseOwner,{
        get:function (target,key){
          console.log(`${key}属性被访问!`)
          return target[key];
        },
        set:function(target,key,value){
          if(target[key]===value){
            return;
          }
          target[key] = value;
          return target[key];
        },
      })
      console.log(proxyOwner);
      proxyOwner.price = 1300;// 对被代理对象的修改
      proxyOwner.remark = &#39;采光点好!&#39;;
      console.log(proxyOwner.price);// price属性被访问
    • 🎜🎜_ rawValue🎜: 전달된 매개변수가 객체현재 참조 값에 해당하는 원래 값을 저장하는 데 사용됩니다. /code> , 변환 전 원래 값을 저장하는 데 사용. 그렇지 않은 경우 _ value는 _ rawValue와 동일합니다. 🎜
    • 🎜🎜_ value🎜: ref의 현재 값을 저장하는 데 사용됩니다. 전달된 매개변수가 객체인 경우 입니다. 저장하는 데 사용됩니다. 반응 함수에 의해 변환된 값입니다. 그렇지 않으면 _값은 _rawValue와 같습니다. 위의 예에서 우리는 참조 유형 데이터의 경우 그 값이 프록시 객체라는 것을 알 수 있습니다. 이는 실제로 데이터를 캡슐화한 후의 반응형 객체입니다(나중에 설명합니다). 먼저 아래 그림을 보고 _rawValue가 반응형 처리가 되지 않은 원래 값임을 확인합니다. 그런 다음 반응형 응답으로 처리된 값인 프록시 객체인 _value를 살펴보겠습니다. 🎜
      🎜🎜_ rawValue🎜 및 🎜_ value🎜는 참조 유형 데이터를 응답적으로 처리해야 하는지 여부를 구분하기 위한 것입니다. 🎜
    🎜이미지. png🎜
    • 🎜🎜value🎜: 현재 값이 저장됩니다. 🎜
    🎜이제 ref가 데이터에 대해 어떤 속성을 캡슐화하는지 알았으니 소스 코드가 위의 6가지 속성에 값을 할당하는 방법을 살펴보겠습니다. 🎜
    • 🎜🎜ref 함수 🎜: Vue3가 개발자에게 공개하는 것은 실제로 createRef 함수를 캡슐화하는 ref 함수입니다. 🎜
      // 源码位置:core-main/packages/reactivity/src/reactive.ts
      // Vue3中暴露给开发者的是reactive方法
      export function reactive(target: object) {
        // 判断target是否只读,是就不做处理
        if (isReadonly(target)) {
          return target
        }
        return createReactiveObject(
          target,
          false,
          mutableHandlers,
          mutableCollectionHandlers,
          reactiveMap
        )
      }
    • 🎜🎜createRef 함수🎜: 두 개의 매개변수가 있습니다. 하나는 처리에 대해 응답할 데이터이고, 다른 하나는 데이터가 다음과 같은지 여부를 결정하는 입니다. shallowRef로 정의된 데이터입니다. 주로 하는 일은 현재 rawValue(아직 응답 처리되지 않은 데이터)가 ref 타입 데이터인지 판단하고 RefImpl 인스턴스 객체를 생성하는 것입니다. 🎜<pre class="brush:js;toolbar:false;">function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow) }</pre>
    • RefImpl类:创建RefImpl类给_ rawValue和_ value属性赋值,判断当前定义的ref数据是否为shallowRef定义的数据,然后获取响应性值时对数据依赖进行收集并返回_ value,修改响应式值时修改并通知依赖更新。

      ref定义的数据为什么需要带.value调用数据? 就是因为RefImpl类暴露给实例对象的get、set方法是value,所以在调用的时候,需要带上。

    Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

    其实,RefImpl实例关键就在于trackRefValue(this)triggerRefValue(this, newVal)的两个函数的处理,我们大概也知道它们就是依赖收集、依赖更新。这里就不一一探讨。

    揭秘Reactive

    上面也说了reactive封装数据的用法,它只支持传入引用类型数据(数组、对象),如果需要在reactive中使用基础类型只能放在对象中。既然这样我们来探讨一下reactive函数究竟做了什么?

    const arrReactive = reactive([1, 3, 2]);// 数组类型
    const objReactive = reactive({  // 对象类型
      name: &#39;sapper&#39;,
      hobboy: [&#39;吉他&#39;, &#39;原神&#39;]
    })
    const changeValue = () => {
      arrReactive[1] = 4;
      objReactive.name = &#39;工兵&#39;;
      objReactive.hobboy[1] = &#39;滑冰&#39;;
      console.log(&#39;arrReactive&#39;,arrReactive);
      console.log(&#39;objReactive&#39;,objReactive);
    }

    Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명从上图可以看出,使用reactive封装的数据返回的都是一个proxy对象,proxy就是代理,如把一个对象代理到另一个对象,好比如房子所有者,代理房子给二手房东销售,二手房东就可以拥有房子销售权利。从上图我们可以看到Proxy对象有三个属性:

    • [[Handler]]: 创建Proxy对象传入的第二个参数,是对当前需要代理的目标target进行一些相关配置处理。

    • [[Target]]:需要代理的目标target,也就是被代理的目标。

    • [[IsRevoked]]:表示是否可撤销,生成可撤销的proxy对象用Proxy.revocable()方法。 那么Proxy对象可以做什么?我们看看下面例子:

      const houseOwner = {home:&#39;房源&#39;,price:1200,type:&#39;一房一厅&#39;};
      const proxyOwner = new Proxy(houseOwner,{
        get:function (target,key){
          console.log(`${key}属性被访问!`)
          return target[key];
        },
        set:function(target,key,value){
          if(target[key]===value){
            return;
          }
          target[key] = value;
          return target[key];
        },
      })
      console.log(proxyOwner);
      proxyOwner.price = 1300;// 对被代理对象的修改
      proxyOwner.remark = &#39;采光点好!&#39;;
      console.log(proxyOwner.price);// price属性被访问

    从这个例子,可以看出Proxy对象的第二个参数给代理目标带上相关属性:set方法、get方法,再回到reactive封装的数据中,数据的Handler属性给数据带上了五个属性:deletePropertygetsethasownKeys。这五个属性怎么来的?我们一起探讨一下Vue3的源码实现:

    // 源码位置:core-main/packages/reactivity/src/reactive.ts
    // Vue3中暴露给开发者的是reactive方法
    export function reactive(target: object) {
      // 判断target是否只读,是就不做处理
      if (isReadonly(target)) {
        return target
      }
      return createReactiveObject(
        target,
        false,
        mutableHandlers,
        mutableCollectionHandlers,
        reactiveMap
      )
    }

    createReactiveObject函数主要为了创建Proxy实例对象,参数传了五个属性: target(目标数据)、isReadonly(target是否只读)、mutableHandlers(ProxyHandler)、mutableCollectionHandlers(ProxyHandler类型)、proxyMap(数据集合)。我们先了解一波createReactiveObject函数:

    Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명

    • ReactiveFlags:响应式数据标记。

      export const enum ReactiveFlags {
        SKIP = &#39;__v_skip&#39;,// 标记对象不可进行代理
        IS_REACTIVE = &#39;__v_isReactive&#39;,// 是否是Reactive封装的
        IS_READONLY = &#39;__v_isReadonly&#39;,// 是否只读
        IS_SHALLOW = &#39;__v_isShallow&#39;,// 是否是shallowRef封装的
        RAW = &#39;__v_raw&#39;// 是否是proxy原始的target
      }
    • TargetType:target的数据类型。

      const enum TargetType {
        INVALID = 0,
        COMMON = 1,// Array、Object类型
        COLLECTION = 2 // Set、Map、WaekMap、WeakSet类型
      }
    • baseHandlers:对于Array、Object类型数据,Proxy实例的第二个参数。传入的baseHandlers就是mutableHandlers。这个函数主要是为了给Proxy对象带上五个属性。

      // 源码位置:core-main/packages/reactivity/src/baseHandlers.ts
      export const mutableHandlers: ProxyHandler<object> = {
        // createGetter() 主要实现依赖收集和Reflect.set(target, key, value, receiver)
        get,
        // createSetter() 主要实现通知依赖更新和Reflect.get(target, key, receiver)
        set,
        // deleteProperty() 主要是删除target的指定key的属性Reflect.deleteProperty(target, key)
        deleteProperty,
        // has() 主要是判断target是否存在指定key的属性,Reflect.has(target, key)
        has,
        // ownKeys() 主要是获取target的key数组,Reflect.ownKeys(target)
        ownKeys
      }
    • collectionHandlers:对于Set、Map、WaekMap、WeakSet类型数据,Proxy实例的第二个参数。传入的baseHandlers就是mutableCollectionHandlers。mutableCollectionHandlers主要是对 set、map、weakSet、weakMap 四种类型的对象进行劫持。

      // 源码位置:core-main/packages/reactivity/src/mutableCollectionHandlers.ts
      export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
        get: /*#__PURE__*/ createInstrumentationGetter(false, false)
      }
      function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) {
        const instrumentations = shallow? 
          isReadonly? shallowReadonlyInstrumentations: shallowInstrumentations
          : isReadonly? readonlyInstrumentations: mutableInstrumentations
      
        return (target: CollectionTypes,key: string | symbol,receiver: CollectionTypes) => {
          ...
          return Reflect.get(
            hasOwn(instrumentations, key) && key in target? instrumentations:target,
            key,
            receiver
          )
        }
      }

    总结

    • ref:定义基本数据类型、引用数据类型的响应式。封装数据类型为ref类型,主要就是创建了RefImpl实例对象
    • reactive:定义引用类型数据的响应式,不支持基本数据类型,如果需要写基本数据类型只能是放在对象中。封装数据为reactive类型,主要是创建了Proxy实例对象,通过Reflect实现数据的获取与修改。

    (学习视频分享:vuejs入门教程编程基础视频

위 내용은 Vue3의 두 가지 주요 반응형 도구인 ref 및 반응성에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제