One. Composite API

Previous component TAB pain points

Usually, a business logic is scattered among different options (lifecycle, calculation properties, etc.), and a complex component may have multiple business logic points, so these different salesman logic points are scattered in the same option. For example, a methods option may have methods to complete different business logic. Therefore, it will be very difficult to read the code. Often, a logical reading needs to jump back and forth between Methods, Mounted, Watch, and Compouted, especially when there are complex and different logical blocks in each option

data(){
  return{}},methods: {// Get the user list
  getUserList(){
    // 100 lines of code
  },

  // Get the list of roles
  getRoleList(){
    // 100 lines of code}},computed: {// List of users in descending order
  orderUsers(){
    // 100 lines of code
  },

  // Group list of roles
  RoleGroup(){
    // 100 lines of code}},mounted(){
  // Get the user list action
  // 50 lines of code

  // Get the list of roles
  // 50 lines of code
}
Copy the code

For example, the above component has two logics, user and role, scattered in each option. It is very difficult to complete the analysis of one of the logics. If the component is more complex than this, the reading can be imagined

Composite API (split logic)setup

Use various functions in setup to create data, computed, lifecycle hook functions, and so on, so you can encapsulate properties that perform the same logic into a single module, and then expose all the modules to the component in Setup.

Avoid the use ofthis

Setup calls are made before data, computed, and methods are resolved, so you can’t call data directly from setup through this

Data declared in an external call to Setup

Setup is a function that returns a final return created with reactive data ref, computed properties, and so on, just like a normal TAB declaration.

How to use API functions in Setup

1. Create reactive data (same asdataTAB)

  1. ref
  2. reactive
  3. toref
  4. torefs
import { ref, toRef, toRefs, reactive } from 'vue'
/ / create
const name = ref('Joe')
const student = reactive({name:'Joe'})
// Keep the reference connection
const sName = toRef(student,'name')
const {sName} = toRefs(student)

return { name,student }
Copy the code

The role and distinction of the above four are explained in detail

2. Register lifecycle hooks

  1. beforeCreate,created: You don’t have tosetupBecausesetupIs aroundbeforeCreatecreatedLifecycle hooks run, so you don’t need to explicitly define them. In other words, any code written in these hooks should be written directly insetupFunction.

2. Rename beforeDestroy to beforeUnmount 3. Rename destroyed to unmounted

import { onMounted } from 'vue'
setup(){
  onMounted(() = >{})}Copy the code

3. Calculate attributes

computed

import { computed,ref } from 'vue'

const stu = reactive({name:'Joe'.age:20})
const name = computed(() = > stu.name)
const age = computed(() = > stu.age)

return { stu, name, age }
Copy the code

4. Listen

The watch function takes three arguments

  1. A reactive reference or getter that you want to listen for
  2. A callback

3. Optional configuration options

import { ref, watch } from 'vue'

const counter = ref(0)
watch(counter, (newValue, oldValue) = > {
  console.log('The new counter value is: ' + counter.value)
})
Copy the code

5. Access the data in the props

Setup takes two arguments:

  1. props
  2. context ( { attrs, slots, emit } )
import { toRefs, computed }

setup(props){
const { name } = props
const comName = computed( () = > name)
return comName
}
Copy the code

The deconstruction of ES6 eliminates the responsiveness of the props. When the name of the props changes, the comName does not change and the response connection can be preserved using toRefs

import { toRefs, computed }

setup(props){
const { name } = toRefs(props)
const comName = computed( () = > name.value)
return comName
}
Copy the code

Computed changes as the name in props changes

6. Emit throws events

The setup second parameter context contains the attrs, slots, and emit attributes

emits:['nameChange'].setup(props,{emit}){
  emit('nameChange'.'Joe')}Copy the code

7. Element ref reference

vue2.x

<div ref="myRef"></div>
Copy the code
this.$refs.myRef
$refs retrieves an array if the element is cyclic, i.e., multiple refs with the same name
Copy the code

vue3.x

<div ref="myRef1"></div>
<button @click="showRef"> showRef </button>
Copy the code
setup(){
 const myRef1 = ref()
 
 function showRef(){
   console.log(myRef1)
 }
 
 return { myRef1,showRef }
}
Copy the code

When there are multiple refs with the same name, the usage also changes, as detailed at the end of this article.

8. Invoke the route object

UseRouter, useRoute

import { useRouter, useRoute } from 'vue-router'

setup(){
    const router = useRouter()
    const route = useRoute()
}
Copy the code

Note that it must be used at the top level of setup, such as the one below, which is problematic

import { useRouter, useRoute } from 'vue-router'

setup(){
    function nameChange(){
        const router = useRouter()
        const route = useRoute()
        console.log(router) // undefined
        console.log(route) // undefined
    }
    
    return { nameChange }
}
Copy the code

9. Invoke the vuex object

Vuex 4.x supports VUE3, and currently vuex is used in setup and map helper functions are not available.

useStore

import { useStore } from 'vuex'
import { computed } from 'vue'

setup () {
    const store = useStore()
    const userName = computed(() = > store.state.user.userName )
    return { userName }
  }
Copy the code

It is also important to note that it must be used at the top level of setup, such as the following, which is problematic

import { useStore } from 'vuex'

setup(){
    function nameChange(){
        const store = useStore()
        console.log(store) // undefined
    }
    
    return { nameChange }
}
Copy the code

The differences and functions of REF, Reactive, toRefs and toRef

1. Add the response status

1.ref

Ref is a single (primitive type) wrapped in a mutable responsive object with a value attribute

<template>
  <div>{{ name }}</div>
  <div>{{ name.value }}</>
</template>

import {ref} from 'vue'

const name = ref('Joe')
console.log(name.value)  / / zhang SAN

return {name,stu:{name}}
Copy the code

When accessed in a template, shallow refs are unpacked without a. Value. Nested deep structures require.value

2.reactive

Reactive creates reactive state for JS objects

<template>
  <div>{{ stu.name }}</div>
</template>

import { reactive } from 'vue'

const stu = reactive( {name: 'Joe'})console.log( stu.name )  / / zhang SAN

return {stu}
Copy the code

The difference between:

Ref is used for the creation of reactive data of primitive data types, and Reactive is used for the creation of reactive data of objects.

Ref uses primitive types, reactive uses objects.

const stu = ref({name:'Joe'})
console.log(stu)
Copy the code

First of all, the above code is fine, at least syntactically permissible. So let’s see what’s going to come out



You can seestuItself isRefType, no problem, but.valueThe value of it isProxy. Vue3’s bidirectional binding is implemented using ES6ProxyImplemented by proxy,reactiveInternally, reactive state is added in the same way.

It can be seen that ifrefThe function is passed inObject, which is eventually calledreactive.

In addition, ifreactiveThe incoming isBasic data typesIt’s not responsive, the data changes, the view doesn’t change.

soBasic data typesuseref.Complex data types (the ultimate prototype of Array is also Object)usereactive

2. Keep the response connection

ToRef, toRefs

  <template>
    <div>{{ showAge }}</div>
    <button @click='changeAge'>changeAgeBtn</button>
  </template>
  
  setup: () = > {
    const stu = reactive({
      name: {value:'Joe'
      },
      age:24
    })
    let {age} = stu
    const changeAge = function(){
      age += 1
    }
    const showAge = computed(() = >{
      return 'My age is' + age
    })
    return { showAge,changeAge }
  }
Copy the code

Although STU is a reactive state added using Reactive, the deconstruction of ES6 eliminates the reactive state, where age simply copies the value but eliminates the responsiveness, and calls to changeAge to change the value of age do not trigger computed or view updates.

This problem only occurs when the base type is deconstructed, if the deconstruction retrieves a name. Because of the nature of the reference type, it points to THE STU, which triggers the response state of the STU, visually equivalent to the name preserving the response state

We can use toRef, toRefs to wrap the data we want to deconstruct as ref, preserve the reference link to the source object and modify the response state above code

  <template>
    <div>{{ showAge }}</div>
    <button @click='changeAge'>changeAgeBtn</button>
  </template>
  
  setup: () = > {
    const stu = reactive({
      name: {value:'Joe'
      },
      age:24
    })
    let {age} = toRefs(stu)
    // let age = toRef(stu,'age')
    const changeAge = function(){
      age.value += 1
    }
    const showAge = computed(() = >{
     return 'My age is' + stu.age
     // return 'my age is' + age.value
    })
    return { showAge,changeAge }
Copy the code

If you change the value of age, stu.age will change, no matter which one of them changes. Both trigger computations and change views

The difference between:

ToRefs can wrap multiple data, but does not create non-existent properties

const { name,age } = toRefs(stu)
Copy the code

ToRef specifies a property and returns an available ref even if the property does not exist

const name = toRef(stu,'name')
const addres = toRef(stu,'addres') // Returns an object with a value attribute even if it does not exist
Copy the code

Custom event $emit

Vue3 has an emit TAB where you must display the name of the event you want to throw, which is the key to differentiating custom component native events from custom events

emit:['changeAge']
Copy the code

1. Customize the V-Model component

The biggest change with VUe2.X is that components can be bound to multiple V-Models

V – model vue2. X

During the Vue2.X era, when multiple data from a packaged component required v-Model two-way data flow requirements, we mostly had two options:

  1. syncModifier, makepropThe child component can be changed.
  2. Multiple pieces of data are packaged into one large object, and the parent and child components are then deconstructed and broken up
  3. After the data is manipulated internally by the child component, the$emitAn event is thrown with parameters, which are then captured by the parent component and reassigned to a prop defined by the child component as follows (not used here)v-modeltheDefault event nameandpropBut in themodelThe options display is definedThe event nameandprop)

sub.vue

<template>
  <div>
    <! -- v-model -->
    <input type="text" :value="name" @input="emit('modelName',$event.target.value)">
    <! -- V-model -->
    <input type="text" :value="name" @input="emit('changeAge',$event.target.value)">
  </div>
</template>
<script>
export default {
  props: {name:String.age:Number
  },
  model: {prop:'name'.event:'modelName'}},</script>
Copy the code

parent.vue

<template>
  <sub v-model="name" :age="age" @changeAge="changeAge" />
</template>
<script>
export default {
  data(){
    return {
      name:'Joe'.age:20}},methods: {changeAge(param){
      this.age = param
    }
  }
}
Copy the code

Vue3 v – model

1. Modifyv-modelThe defaultThe event nameandprop“And no longer neededmodeloptions

parent.vue

<my-component v-model:title="parTitle"></my-component>
Copy the code

myComponent.vue

<input type:"text" :value="title" @input="$emit('update:title',$event.target.value)" />

props:{
  title:String
},
emit: ['update:title']
Copy the code

The child component throws an Update: Prop event that takes v-Model: Prop when the parent component binds v-Model. Specify prop as V-model. The emit option registers custom events to be discarded because the native modifier is removed to distinguish native events from custom events.

2. Multiple v – model

On top of that, you can specify multiple prop options

<my-component v-model:title="parTitle" v-model:age="parAge"></my-component>
Copy the code

myComponent.vue

<input type:"text" :value="title" @input="$emit('update:title',$event.target.value)" />
<input type:"text" :value="age" @input="$emit('update:age',$event.target.value)" />

props:{
  title:String.age:Number
},
emit: ['update:title'.'update:age']
Copy the code

V – model modifier

Vue3 adds a custom modifier parent. Vue in addition to the three hard-coded V-model modifiers

<my-component v-model:title.show="myText"></my-component>
Copy the code

myComponent.vue

props:{
  title:String.titleModifiers: {default: () = >({})}},emit: ['update:title'].methods: {emitValue( value ){
    if(this.titleModifiers.show){
      this.$emit('update:title', value)
    }
  }
}
Copy the code

The value of the modifier is obtained in a prop named a [prop]Modifiers, for example: the title modifier show is obtained in a prop named titleModifiers

Other changes

1.nativeModifier removal

Events that are triggered on a child component that are not defined in the EMIT option are now treated as native events.

2.template v-for

It is now recommended to write the template V-for key directly on the template tag

More than 3. Ref

vue2.x

<div v-for="v in list" :key="v.key" ref="myRef"></div>

this.$refs.myRef[0]
Copy the code

The same ref is converted to an array for vue3.x

<div v-for="v in list" :key="v.key" :ref="setRef"></div>

setup(){
  let refList = []
  const setRef = el= > {
    refList.push(el)
  }
  return { setRef }
}
Copy the code

Now you bind it to a function that stores the DOM flexibly

A pit

1. The user-defined component v-show is invalid

Vue3’s template supports multiple nodes, but with a caveat

V-show does not work on multi-root components. V-show requires a top-level root node to control show and hide by style, which is obviously problematic with multiple roots. V-if works because it directly controls whether the component is loaded or not

conclusion

This is far from the case with vue3. This note only records changes at the usage level, and it is highly recommended that you review the documentation for migrating VUe2 in detail. V3.cn.vuejs.org/guide/migra…