reactive, ref, toRef and toRefs in vue3

reactive

reactive is used to create reactive objects, it returns a reactive proxy of an object. That is: the object it returns and the objects nested in it will be wrapped by Proxy; when the responsive object is accessed, the getter method is triggered; when the responsive object is modified, the setter method is triggered. When using reactive objects, we can access and modify data like ordinary objects.

Sample code using reactive

<template>
  <div> 
    {
    
    {
    
     state.name }} --- {
    
    {
    
     state.age }}
  </div>
</template>
<script setup> 
import {
    
     reactive } from 'vue';
const state = reactive({
    
    
  name: 'jack',
  age: 22
})
</script>
<style scoped>
</style>

The realization principle of reactive

Reactive is implemented using ES6's Proxy object. When we use the reactive function to process an object in a responsive manner, Vue3 will create a Proxy to intercept the reading and modification operations of all properties of the object, so as to monitor the changes of properties and trigger related responsive updates when they change. .

The simple schematic code of the reactive implementation principle is as follows:

function reactive(obj) {
    
    
  if(typeof obj !== 'object' || obj === null) {
    
    
    return obj;
  }

  // 防止响应式重复包裹
  if(obj.__v_reactive) {
    
    
    return obj;
  }

  const observed = new Proxy(obj, {
    
    
    get(target, key, receiver) {
    
    
      // 收集依赖
      track(target, TrackOpTypes.GET, key);

      // 递归获取嵌套属性
      const res = Reflect.get(target, key, receiver);
      return isObject(res) ? reactive(res) : res;
    },
    set(target, key, value, receiver) {
    
    
      // 更新属性值
      const oldValue = Reflect.get(target, key, receiver);
      let result = true;
      if(oldValue !== value) {
    
    
        result = Reflect.set(target, key, value, receiver);
        // 触发更新
        trigger(target, TriggerOpTypes.SET, key, value, oldValue);
      }
      return result;
    },
    deleteProperty(target, key) {
    
    
      const hasKey = hasOwn(target, key);
      const oldValue = target[key];
      const result = Reflect.deleteProperty(target, key);
      if(hasKey && result) {
    
    
        // 触发更新
        trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue);
      }
      return result;
    }
  });

  // 标记为响应式对象
  observed.__v_reactive = true; 
  return observed;
}

In the above code, the reactive function receives an object obj, and if obj is not an object or null, returns the original value. If obj has been processed as a responsive object, the responsive object will be returned directly.

Precautions for using reactive

  1. reactive can only handle objects and arrays. If parameters other than objects or arrays are passed in, they will be returned directly without responsive processing.

  2. For a given object, reactive will recursively collect the dependencies of all its sub-properties, so in actual development, try not to nest too deep, otherwise performance may be affected.

  3. Objects processed by reactive cannot be directly used for destructuring assignment operations. It is recommended to use the toRefs function provided by Vue3 to convert reactive objects into ordinary objects before performing operations.

  4. In the setup function of the component, it is necessary to use ref or reactive to process the data responsively before it can be used. Reactive objects created outside the function must also be used in the setup function of the component to ensure that the responsiveness takes effect.

ref

Regarding the related characteristics of ref, I have talked about its usage for registering references of elements or subcomponents in the previous blog, so I will not fully talk about it here, and only discuss the responsiveness that was not mentioned in the previous blog.

ref takes an internal value and returns a reactive, mutable ref object that has only one property .value pointing to its internal value. It wraps a primitive type of data into a reactive object.

The ref object is mutable, and we can modify its value through the .value attribute. It is also reactive, i.e. all operations on .value will be tracked and writes will trigger side effects associated with it.

If an object is assigned to ref, then this object will be converted into a deeply reactive object through reactive(). This also means that if the object contains nested refs, they will be deeply unwrapped.

The realization principle of ref

Ref is implemented based on the reactive and proxy APIs in Vue 3, and proxy sets custom behaviors on objects by creating interceptor objects. It is used to intercept read and write operations on the ref object, so as to notify the Vue responsive system to update the view when the ref value changes.

The simple schematic code of ref implementation principle is as follows:

function ref(value) {
    
    
  return reactive({
    
    
    value,
    get unbox() {
    
    
      return this.value
    }
  })
}

Here, we make value reactive by using value as an attribute of the reactive object. At the same time, we provide a convenient method to get the value of value through the unbox attribute.

Notes on using ref

  1. ref can only be used to wrap simple types of data, such as independent basic data types such as strings, numbers, and Boolean values, or data of reference types such as objects, arrays, and functions. It is not recommended to use ref for wrapping complex nested data structures, as this increases the complexity of handling and maintenance.

  2. When using ref inside a component, it is recommended to create a ref member variable inside the setup() function and use template refs in the component template to refer to it.

  3. ref can only be used to wrap mutable variables, and should not be used to wrap immutable variables or constants, because this will make it impossible to update the value of the variable.

  4. When operating on a ref object, you should use the .value attribute to access its internal responsive value instead of directly manipulating the ref object itself.

  5. Do not define additional properties or methods on the ref object, as these will not be tracked by the reactive system and will not trigger view updates. If you need to define properties or methods on a ref object, you should use a reactive object to wrap them.

toRef and toRefs

toRef and toRefs are two very important tool functions in vue. They can convert the properties of a responsive object into a Ref object or a collection of Ref objects, so that these properties can be used in components.

  1. toRef: The toRef function converts one of the properties of the responsive object into a Ref object.

    A simple example of toRef

    <template>
      <div> 
        {
          
          {
          
           nameRef}} 
      </div>
    </template>
    <script setup>  
    import {
          
           reactive, toRef } from 'vue'	
    const state = reactive({
          
          
      name: 'Vue 3',
      version: '3.0.0'
    })	
    const nameRef = toRef(state, 'name')
    </script>	
    <style scoped>	
    </style>	
    
  2. toRefs: The toRefs function converts all properties of a responsive object into a collection of Ref objects.

    A simple example of toRefs

    <template>
      <div> 
        {
          
          {
          
           refs.name }} ---{
          
          {
          
           refs.version }}
      </div>
    </template>
    <script setup>  
    import {
          
           reactive, toRefs } from 'vue'
    
    const state = reactive({
          
          
      name: 'Vue 3',
      version: '3.0.0'
    })
    
    const refs = toRefs(state)
    </script>
    <style scoped>
    </style>
    

Comparison of the use of ref and reactive

Both Ref and Reactive are reactive objects. Their difference is:

Ref is a basic type of responsive container, accessed through .value, suitable for responsive data of basic types or simple objects.

Reactive is an object-level responsive container, suitable for complex objects or arrays of responsive data.

The following is a sample code showing the difference and usage scenarios of Ref and Reactive:

<template>
  <div> 
    {
    
    {
    
     count }} ---{
    
    {
    
     doubleCount }} <br>
    {
    
    {
    
     state.count }} ---{
    
    {
    
     state.doubleCount }}
  </div>
</template>
<script setup>  
import {
    
     ref, reactive,watch } from 'vue'
// 1. Ref示例代码
const count = ref(0)
const doubleCount = ref(0)
watch(count, () => {
    
    
  doubleCount.value = count.value * 2
})
// 2. Reactive示例代码
const state = reactive({
    
    
  count: 0,
  doubleCount: 0
})
watch(() => state.count, () => {
    
    
  state.doubleCount = state.count * 2
})
</script>
<style scoped>
</style>

In the above code, we use the Ref object and the Reactive object to realize the responsive processing of the same data. It can be seen that the Ref object is simple to use and is suitable for a single basic type of data, while the Reactve object is more complicated and is suitable for complex object and array data.

OK, this is the end of the introduction to the usage methods of reactive, ref, toRef and toRefs in vue3. If you like it, please like, follow and add to favorites!

Guess you like

Origin blog.csdn.net/w137160164/article/details/131146690