[front end] catch all at once -- a new feature of vue3 composition API

Write in front

Before experiencing Vue3, let's learn what are the highlights of Vue3.

There are 6 features in total:

  • Performance (about 2 times faster than vue2's runtime)
  • Tree shaking support
  • Better TypeScript support
  • Composition API
  • Custom Renderer API
  • Fragment, Teleport, Suspense

1. Origin of vue3 setup

  1. Understanding: vue3 The combination api stage of 0 is setup
  2. Setup all data methods are configured in setup
  3. setup has two return values:
    1. If an object is returned, the properties and methods in the object can be used directly in the template
    2. If you return a rendering function, you can customize the rendering content
  4. be careful:
    1. vue3.0 should not be mixed with the configuration of vue2
    2. vue2 configuration (data, methods, computed, etc.) is a method that can access the setup property of vue3
    3. Inaccessible vue2 configurations in setup (data, methods, computed, etc.)
    4. In case of duplicate names, vue3 prevail
  5. setup cannot be an async function, because the return value is no longer the return object, but promise. The template cannot see the properties in the return object (promise can also be obtained by using suspend and asynchronous components later)

2. ref function

  • Function: used to define a responsive data
  • Syntax: const name = ref(initValue)
    • Create a reference object (ref object for short) containing responsive data
    • Operation data in js: name value
    • Reading data from the template: value is not required, but < div > {{name}} < / div >
  • be careful:
    • Accepted data: basic type, object type
    • Basic data type: the response type is object get and set of defineproperty() are used for setting and value taking operations
    • Data of object type: a new function in vue3 - reactive function (actually proxy proxy) is used internally

3. reactive function

  • Function: it is used to define the responsive data of an object type (the ref function is used instead of the basic type)
  • Syntax: const proxy object (proxy) = reactive (source object) receives an object or array and returns a proxy object (proxy instance object for short)
  • The response defined by reactive is "deep-seated", and all objects in the object are responsive
  • The internal proxy implementation based on es6 operates through the internal data of the proxy object

Deconstruction syntax cannot be used for objects that have been reactively processed, because they will lose the responsive feature. You can use toRefs to convert each attribute of reactive into a ref responsive, so that you can perform responsive processing.

Difference between ref and reactive

reactive is used to convert object data into a response, similar to vue2's observable, while ref is used to obtain a response from a separate or basic data type.

Why are there two APIs in vue3 that convert data into responsive data? Let's explain in detail:

  • Ref accepts an internal value and returns a responsive and variable ref object with a single property that points to the internal value value
  • reactive accepts an object and returns a responsive copy of the object, which turns each element in the object into a ref object

In short, reactive can convert object data into response data, and each element in the object can be converted into ref response data; Ref can not only convert object data into response, but also handle basic data types (string, boolean, etc.).

The reason for this difference is that the response expression in vue3 is implemented based on proxy, and the target of proxy must be a reference data type, that is, an object stored in heap memory and referenced by a pointer. The reason why it is an agent's reference data type is that each assignment of a simple data type is new data, and the agent cannot be performed at all. Therefore, it is difficult to implement the response of a simple data type.

What should we do if we want to get a response of a simple data type?

This is also taken into account in vue3. You can perform responsive processing of simple data types through Ref. Ref hangs the value to value by creating an internal state, so the object generated by ref needs to pass Value get use. The listening obtained by rewriting get/set also depends on the implementation of reactive.

In this way, ref can handle both simple data types and reference data types responsively. In practice, we should avoid using reactive as vue2's data to declare all variables at the top, but should declare them nearby in combination with specific applications and logic.

class RefImpl<T> {
  private _value: T

  public readonly __v_isRef = true

  constructor(private _rawValue: T, public readonly _shallow = false) {
    this._value = _shallow ? _rawValue : convert(_rawValue)
  }

  get value() {
    track(toRaw(this), TrackOpTypes.GET, 'value')
    return this._value
  }

  set value(newVal) {
    if (hasChanged(toRaw(newVal), this._rawValue)) {
      this._rawValue = newVal
      this._value = this._shallow ? newVal : convert(newVal)
      trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
    }
  }
}
...
const convert = <T extends unknown>(val: T): T =>
  isObject(val) ? reactive(val) : val
...

4. Responsive principle in vue3

  • vue2's responsive principle:
    • Object type: through object Defineproperty() intercepts the reading and modification of properties (data hijacking)
    • Array type: intercept by overriding a series of methods to update the array. (wrap the change method of the array)
  Object.defineProperty(data,"count",{
    get(){},
    set(){}
  })
  • Problems:

    • When adding or deleting attributes, the interface will not be updated synchronously
    • Modify the array directly through the following table, and the interface will not be updated automatically
  • Response principle of vue3

    • proxy: intercept any attribute changes in the object, including reading and writing attribute values, adding and deleting attribute values, etc
    • Reflect through reflect: operate on the properties of the proxied object

5. Difference between reactive and ref

  • Define data
    • ref: used to define basic data types
    • reactive: used to define reference data types
    • Note: ref can also be used to define reference data types, which will be automatically converted to proxy objects through ractive
  • principle
    • ref: through object The set and get properties of defineproperty () implement responsive (data hijacking)
    • reactive: the responsive (data hijacking) is implemented through the Proxy, and the data inside the object is accessed through the Reflect operation
  • use
    • Ref: the data defined by ref needs to pass Value, which is not needed when the template reads data value
    • Reactive: the data defined by reactive does not need to be value to set and read

6. Calculate attributes and monitor

  • It is consistent with the computed configuration function in vue2
  • Writing method:
import {computed} from "vue";
setup(){
  const sum = computed(()=>{
    return num1 + num2;
  })
}
import {computed,reactive} from "vue"
setup(){
  const person = reactive({
    firstName:"wen",
    lastName:"bo"
  })
  //Abbreviation
  let fullName = computed(()=>{
    return person.firstName + "-" + person.lastName;
  });
  
  //complete
  let fullName = computed(()=>{
    get(){
      return person.firstName + "-" + person.lastName;
    },
    set(value){
      const newArr = value.split("-");
      person.firstName = nameArr[0];
      person.lastName = nameArr[1];
    }
  })
}

7. watch function

  • It is consistent with the watch configuration function in vue2
  • be careful:
    • When monitoring the responsive data defined by reactive, oldValue cannot be obtained correctly, and deep monitoring is forcibly enabled (deep configuration failed)
    • The deep configuration is valid when monitoring an attribute in the reactive defined responsive data
let person = reactive({
  name:"wenbo",
  age:18,
  job:{
    job1:{
      salary:20
    }
  }
})

// Scenario 1: monitor the responsive data defined by ref
watch(sum,(newValue,oldValue)=>{
  console.log("sum Changed",newValue,oldValue);
},{immediate:true})

// Scenario 2: monitor the responsive data defined by multiple ref s
watch([sum,msg],(newValue,oldValue)=>{
  console.log("sum or msg Changed",newValue,oldValue);
})

/*Scenario 3: monitor reactive defined responsive data
  If the watch monitors reactive defined responsive data, the oldValue cannot be obtained correctly
  If the watch monitors responsive data defined by reactive, the deep monitoring is forced on
  deep does not take effect at this time
*/
watch(person,(newValue,oldValue)=>{
  console.log("perosn Changed",newValue,oldValue);
},{immediate:true,deep:false})

//Scenario 4: monitor an attribute in a responsive data defined by reactive
watch(()=>person.age,(newValue,oldValue)=>{
  console.log("person of age Changed",newValue,oldValue)
})

//Scenario 5: monitor some attributes in a responsive data defined by reactive
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
  console.log("person of name or age Changed",newValue,oldValue)
})

//Special case - the attribute of the listening object is still an object. At this time, deep takes effect and deep listening can be carried out
watch(()=>person.job,(newValue,oldValue)=>{
  console.log("person of job Changed",newValue,oldValue)
},{deep:true})

be careful:

  • There are five situations in which watch listens to objects defined by reactive

  • watch listens to the responsive data defined by ref in two ways:

    • Ref defines basic type data, which cannot be used at this time Value to listen. For example, const num = ref(0). At this time, listening to num.value is equivalent to directly listening to the value (0) of num. think about the change of 0.
    • Ref defines the object data type. In this case, the data processed by ref is the data of ref instance. To listen for changes in an object, you need to monitor the object value listens because the ref object value is a responsive data proxy processed with reactive.

8. watchEffect function

  • Routine of watch: both the monitored properties and the monitored callbacks should be specified
  • Routine of watchEffect: it is not necessary to specify which property to monitor or which property to use in the monitored callback
  • watchEffect is somewhat similar to computed:
    • computed focuses on the calculated value, that is, the return value of the callback function, so the return value must be written
    • watchEffect focuses on the calculation process, that is, the function problem of the callback function, so there is no need to write the return value
let person = reactive({
  name:"wenbo",
  age:18,
  job:{
    job1:{
      salary:20
    }
  }
})

// As long as the data used in the callback specified by warchEffect changes, the callback will be directly re executed
watchEffect(()=>{
  const x = person.name
  const y = person.job.job1.salary
  console.log("watchEffect Triggered")
})

9. Customize hooks function

  • hook function: it is essentially a function that encapsulates the composite api used in the setup function
  • Similar to mixins in vue2
  • Advantages: reuse code to make the logic in setup clearer and easier to understand
<div>pageX: {{point.pageX}},pageY: {{point.pageY}}<div>
  

hooks file usepoint js

import {reactive} from "vue"

const handleClickPoint = ()=>{
  //Realize the mouse "dot" related data
  let point = reactive({
    pageX:0,
    pagey:0
  })
  
  //Implementation of mouse "dot" related methods
  const handlePoint = (event)=>{
    point.pageX = event.pageX;
    point.pageY = event.pageY;
    console.log(event.pageX,event.pageY)
  }
  //Realize the related periodic function of mouse dot
  onMounted(()=>{
    window.addEventListener("click",handlePoint)
  })
  
  onBeforeUnmounted(()=>{
    window.removeEventListener("click",handlePoint)
  })
}

10. toRef function

  • Objects processed by ref and reactive cannot be directly processed by deconstruction, otherwise they will lose their responsive properties
  • Function: create a ref object whose value points to an attribute in another object
  • Syntax: const name = toRef(person,"name")
  • Application: when you want to provide a property in a responsive object separately for external use
  • Extension: toRefs has the same function as toRef, but multiple ref objects can be created in batch. Syntax: toRefs(person)

11. VUE3 life cycle

Other composite APIs

1. shallowReactive and shallowRef

  • shallowReactive: only handle the response of the outermost attribute of the object (shallow response)
  • shallowRef: only the response of basic data type is processed, and the response of object is not processed
  • Use time:
    • If there is an object data, the structure is relatively deep, but only the outer attribute changes when it changes = = "shallowReactive"
    • If there is an object data, the subsequent function will not modify the attributes in the object, but generate a new object to replace = = "shallowRef"

2. readonly and shallowReadonly

  • readonly: change a responsive data into read-only data (deep read-only)
  • shallowReadonly: make a responsive data read-only (shallow read-only)
  • Application scenario: when you do not want the data to be modified

3. toRaw and markRaw

  • toRaw
    • Function: convert a reactive object into a normal object
    • Usage scenario: it is used to read the ordinary object corresponding to the responsive object. All operations on this ordinary object will not cause the page to be updated
  • markRaw
    • Purpose: mark an object so that it will never be called a responsive object
    • Application scenario:
      • Some values should not be set to be responsive, such as complex third-party libraries
      • Skipping responsive transformations can improve performance when rendering large lists with immutable data sources

4. customRef

  • Function: create a custom ref and explicitly control its dependency tracking and update trigger
  • Example:
  <template>
    <input type="text" v-model="str"/>
    <h1>Current value:{{str}}</h1>
  </template>

    <script>
    import {ref, customRef} from "vue";
    export default {
      setup(){
        // Customize a ref: myRef
        const myRef = (value)=>{
          return customRef((track,trigger)=>{
            return{
              get(){
                console.log(`Someone from myRef This data was read in ${value}`);
                track();
                return value;
              },
              set(newValue){
                console.log(`Someone put myRef Changed data to new data ${newValue}`);
                value = newValue;
                trigger();//Notify vue to re resolve the template
              }
            }
          });
        }
        const str = myRef("hello");
        return{
          str
        }
      }
    }
    </script>

5. provide and inject

- Function: realize the communication between grandparents and grandchildren
- Application scenario: the parent component has a provide Option provides data, and the subcomponent has one inject To get usage data

6. Judgment of responsive data

- isRef: Check whether a value is ref object
- isReactive: Check whether a value is reactive Create a responsive agent
- isReadonly: Check whether an object is created by readonly Created read-only proxy
- isProxy: Check whether an object is created by reactive or readonly Created proxy

Notes on using hook in vue3

  1. There is an asynchronous problem in hook

In fact, it can be found in use that hook is essentially a function for extraction, with high flexibility, but it will lead to many problems if it is not considered carefully when it comes to asynchronous logic. Hook can cover asynchronous situations, but it must be executed in setup. When returning valid objects, they cannot be blocked.

There are usually two styles of asynchrony:

  • There are no other external dependencies, just the response variables of rendering. In this case, you can use asynchronous modification in hook by declaring and exposing response variables.

  • It is dependent on the outside and needs to be processed on the use side. In this case, the ability of synchronous operation can be obtained externally by exposing Promise.

  1. this problem

Setup cannot get this because it is between the beforeCreate and created phases of the lifecycle. Of course, we can obtain some capabilities similar to this through the second parameter context of setup, but the ability to operate routes and vuex is limited. For this reason, the latest router@4 , vuex@4 Both provide combined APIs.

Due to vue2 low-level restrictions, these hook s cannot be used. Therefore, you can obtain certain operation capabilities by referring to the instance, or you can obtain the objects mounted on the component instance through getCurrentInstance.

Although the response principle of the composite api is through object Defineproperty rewrites properties in the same principle as vue's response expression, but there are differences in specific implementation methods. Therefore, it does not interoperate with vue's native response expression in setup. As a result, even if the corresponding instance is obtained, there is no way to listen to their response, which can only be used in option configuration.

Common components in vue3

1. Fragment component

In vue2: the component must have a root label

In vue3: a component can have no root tag, and multiple tags will be wrapped inside the Fragment virtual element

Benefits: reduce tag levels and memory usage

2. Teleport

Teleport relies on technology that can move the html structure of components to a specified location

Syntax: < report to = "target location" > < / report >

main.vue

<div name="modal"></div>
<Modal :isOpen="isOpen" @closeModal="closeModal"/>
<button @click="openModal" >open modal</button>

modal.vue

 <teleport to='#modal'>
    <div class="modal-box" v-if="isOpen">
      <slot>this is a modal</slot>
      <button @click="handleCloseModal">close</button>
    </div>
  </teleport>

3. suspense

Render some additional content while waiting for asynchronous components to give the application a better user experience.

Use steps:

  1. Asynchronous import component

  2. Use suspend to wrap the components, and configure default and fallback.

import {defineAsyncComponent} from "vue"
const child =defineAsyncComponent(()=>import("./components/child.vue"))

Reference articles

Write at the end

I am a front-end chicken. Thank you for reading. I will continue to share more excellent articles with you. This article refers to a large number of books and articles. If there are errors and mistakes, I hope to correct them.

For more latest articles, please pay attention to the author's Nuggets account Ichikawa firefly And the front of the official account is gravity.

Keywords: Vue

Added by delboy1978uk on Tue, 28 Dec 2021 05:37:20 +0200