Introduction to the

By the time you finish reading the introduction, it seems to me that you can’t wait to see some of the new features of Vue3.0. Take a look at the magic of the CompositionAPI. Here are three official ways to experience Vue3.0. I personally recommend Vite which offers some configuration out of the box, and very fast speed.

  • VueCli: Official scaffolding, throughvue add vue-nextCan experience.
  • Vite: Also available for official, throughyarn create vite-app <project-name>
  • Vue-next-webpack-preview: The official webpack preview scaffolding

All the cases in this article are carried out using Vite.

Vue development manual series

  • Vue Development Manual – Introduction section view
  • Vue development Manual – Get Started view

Initialize the project

#Initialize the project
yarn create vite-app vue3-dev-example

#Into the project
cd ./vue3-dev-example

#Install dependencies
yarn

#Start the project
yarn dev
Copy the code

When the following screen is displayed, it indicates that the project is running successfully. You can access the Vue content from any serve address in the browser.

Configuration Typescript

TypeScript is used for better type derivation, and there are non-TS versions of the code. So TS here, I’m going to make it as simple as possible.

Rename main.js to main.ts and change the corresponding name in the introduction of index.html

tsconfig.json

Json can be quickly generated using the following command. Before using the command, make sure you have typescript installed locally or you will not be able to use the TSC command.

#Generate a JSON configuration file
tsc --init
Copy the code

Type declaration

Now the project has been almost switched to a TS project, but then it turns out that some module introductions seem to have problems. This is because the module declaration has not been defined yet and you cannot find what is being introduced. Create a vue.d.ts declaration file under SRC.

Type module declaration for all.vue files, then all.vue files will be type declared for imported vue files.

// vue.d.ts edit
declare module '*.vue' {
  import { ComponentOptions } from 'vue';
  const componentOptions: ComponentOptions;
  export default componentOptions;
}
Copy the code

Then import the configuration in tsconfig.json

# tsconfig 
"include": [
  "src/**/*.ts"."src/**/*.tsx"]."exclude": [
  "node_modules"
]
Copy the code

And then you start the project, and you find out

Fragment

One of the new features, prior to Vue3.0, the template had to be wrapped with a node. Therefore, the Templatea component has and can only have one root node. In many cases, this will actually cause a lot of waste. Obviously, my component only has two boxes, but because I split it out, I have to set another layer, which increases the depth of DOM nodes and indirectly consumes performance.

Vue template 2.0 template </div> </template>Copy the code
<template>
  <div>vue3</div>
  <div>template fragment</div>
</template>
Copy the code

setup

In Vue3 you put most of the Options API properties into setup, so you can think of it as a collection. Note that setup itself is executed only once at initialization, and can also be thought of as a lifecycle hook. After the props is initialized, the setup function is executed, which is called only once when the component is initialized. If the component is initialized, setup will not be executed.

<script lang="ts">
export default {
  name: 'App',
  props: {},
  setup (props, context) {
    console.log('setUp ... ')
  }
}
</script>
Copy the code

Note that only content that is actively exposed in setup can be used by template. If it is not exposed, a message will be sent indicating that the variable was not found and not initialized. Using the following example, when commenting out MSG in return, it is not available in template.

<script lang="ts"> export default { name: 'App', props: {}, setup (props, context) {= const msg: String = 'I am message' return {// MSG}} </script>Copy the code

Reactive definition

There is a separation of responses for base and reference types in the Composition API, and the use of refs and Reactive to define different data responses is very different. The following through an example of easy to understand to everyone

  • Base type: REF
  • Reference type: reactive
<template> <div>hello vue composition API ... </div> <p>msg:{{msg}}</p> <ul> <li v-for="value, key in person"> {{key}}--{{value}} </li> </ul> <button @click="updateMsg('update after click... <button @click="updatePerson({name: 'ZhangSan', age: 1)"> "> update Person</button> </template> <script lang="ts"> import {reactive} from 'vue'; import { useRef, useReactive } from './hooks/useMod'; export default { name: 'Home', props: {}, setup (props, context) {// get MSG const {MSG, updateMsg} = useRef() updatePerson } = useReactive() return { msg, updateMsg, person, updatePerson } } } </script>Copy the code
// @wang useMod
import { Ref, ref, reactive } from 'vue';

export function useRef() {
  // Create a default ref
  const msg: Ref<string> = ref<string> ('define value');
  // Update MSG information
  function updateMsg(text: string) :void {
    msg.value = text
  }
  return {
    msg,
    updateMsg
  }
}

export function useReactive() {
  type IPerson =  {
    name: string
    age: number
  }
  const person: IPerson = reactive<IPerson>({
    name: 'wangly'.age: 22
  })
  // Update person information
  function updatePerson(newPerson: IPerson) :void {
    person.name = newPerson.name
    person.age = newPerson.age
  }
  return {
    person,
    updatePerson
  }
}
Copy the code

In the above example, we declare a string and an object responsively, and change them with a button event to test whether the data on the page changes with the response.

ref

When we initialize the primitive type response using ref, we must use the value attribute to make changes when we need to modify the content after initialization. Only the content modified by.value is valid responsive content. Of course, when template is used, you don’t need the.value attribute to get and change a value.

const msg: Ref<string> msg = ref<string> (' ')
// error
msg = 'update value .... '
// god
msga.value = 'update value .... '
Copy the code

reacitve

Reactive initializes the reference type as before and does not change much. Do not try to deconstruct the operation, because it will lose its responsiveness to update. There are two apis to do this.

  • ToRef: Response to wrap a Reacitve member into a ref
  • ToRefs: Wrap all members of Reactive into Reactive.
type IPerson =  {
    name: string
    age: number
  }
  const person: IPerson = reactive<IPerson>({
    name: 'wangly'.age: 22
  })
// toRef
  const name = toRef(person, 'name') => name = a ref()// toRefs
  constparamsReactive = toRefs(person) => { ... All members are ref}Copy the code

Judgment response

Why are responsive judgments provided? In the Composition API, the responsiveness of a variable is lost, and the developer is actively aware of whether the state is a normal variable or a reactive variable.

  • IsRef determines whether a variable isrefThe parcel agent
  • IsReactive determines whether a variable is activatedreactiveThe parcel agent

Once again, this is the first small instance, using the two exported contents in usemod. ts. The two apis are pretty straightforward to understand

 
    / / get the MSG
    const { msg, updateMsg } = useRef()
    / / for the person
    const { person, updatePerson } = useReactive()
    const personList = toRefs(person)
    console.log('MSG is a variable of ref proxy', isRef(msg))
    console.log('person is a variable of the ref agent', isRef(person))
    console.log('MSG is a variable of a reactive proxy', isReactive(msg))
    console.log('person' is a variable of a reactive proxy, isReactive(person))
Copy the code

A read-only variable

This is a new addition to the Composition API that, as its name suggests, produces a variable that can only be read and cannot be changed. If you force changes to values generated by ReadOnly, you will receive unexpected warnings. It is recommended that your variables be wrapped with Readonly when they do not want to be accidentally changed.

<script lang="ts">
import { reactive, toRefs, isRef, isReactive, readonly } from 'vue';
import { useRef, useReactive } from './hooks/useMod';

export default {
  name: 'App'.props: {},
  setup (props, context) {
    / / get the MSG
    const { msg, updateMsg } = useRef()
    / / for the person
    const { person, updatePerson } = useReactive()
    const personList = toRefs(person)
    // Wrap MSG as read-only
    const readOnlyMsg = readonly(msg)
    msg.value = '2222'
    readOnlyMsg.value = '111'
    return {
      msg,
      updateMsg,
      person, 
      updatePerson
    }
  }
}
</script>
Copy the code

Judge read-only variables

As in the reactive case, the generated variable for readonly is accompanied by a judgment function, isReadonly, that passes a value that identifies whether it is a readable property.

const readOnlyMsg = readonly(msg)
console.log('Is MSG readable?', isReadonly(msg))
console.log('Is readOnlyMsg readable?', isReadonly(readOnlyMsg))
Copy the code

Calculate attribute

The Composition API makes very little change to computed attributes. Like Methods, it is defined and exposed to template, and is basically the same as before, except that it is covered by computed data from its previous declaration. Return returns the last value of the evaluated property.

<template>
    <span v-for="item in list" :key="item">{{item}}</span>
    <br>
    <span v-for="item in computedList" :key="item">{{item}}</span></template> <script lang="ts"> import { reactive, computed, ComputedRef } from 'vue'; import { useRef, useReactive } from './hooks/useMod'; export default { name: 'App', props: {}, setup (props, context) { const list: Array<string> = reactive<Array<string>>(['my ', 'name ', 'is ', 'wangly']) ComputedRef<string> = computed((): string => {return 'I am a computed attribute'}) return {list, computedList}}} </script>Copy the code

The listener

Vue3 provides a method function similar to Watch, which is mainly used to record data monitoring and facilitate developers to detect the changes of a variable as a component. However, the new Composition API of Vue2 watch doesn’t change much. Supports simultaneous monitoring of multiple variables.

Listening for a single variable

setup() {
    const count: Ref<number> = ref<number> (0)
    setTimeout(() = > {
      count.value ++
    }, 5000)
    watch(count, (newVal, oldVal) = > {
      console.log('Changed value', newVal)
      console.log('Value before change', oldVal)
    })
    return {
      count
    }
Copy the code

Listening for multiple variables

Just in the first parameter, put all the variables you need to listen in the array and push all the variables to watch. Then you will get the result set before and after the change according to the variables in the array

<script lang="ts">
import { ref, onMounted, provide, watchEffect, Ref, watch } from 'vue'

export default {
  name: 'Home'.props: {},
  setup() {
    const count: Ref<number> = ref<number> (0)
    const sum: Ref<number> = ref<number> (100)
    setTimeout(() = > {
      count.value ++,
      sum.value = 1000
    }, 5000)
    watch([count, sum], (newVal, oldVal) = > {
      console.log('Changed value', newVal)
      console.log('Value before change', oldVal)
    })
    return {
      count
    }
  }
}
</script>
Copy the code

About Reactive

Object monitoring becomes very interesting. You need to wrap a function for you to be recognized by Watch. Similarly, multiple attribute monitoring is also supported, but it actually looks quite strange.

export default {
  name: 'Home'.props: {},
  setup() {
    const { person } = useReactive()
    setTimeout(() = > {
      person.name = 'ying zheng'
      person.age = 1000
    }, 5000)
    watch([() = > person.name, () = > person.age], (newVal, oldVal) = > {
      console.log('Changed value', newVal)
      console.log('Value before change', oldVal)
    })
    return {
    }
  }
}
</script>
Copy the code

Combination of listening

What is combined listening? It means that you can have multiple groups of variables under a watch, and then you can have a listen for multiple groups of data that are passed in, and for the listening result set, the property heap is actually one by one queued. This allows each array element to be treated as a separate listener for data processing.

<script lang="ts">
import { ref, onMounted, provide, watchEffect, Ref, watch } from 'vue'
import { useReactive, useRef } from './hooks/useMod'

export default {
  name: 'Home'.props: {},
  setup() {
    const { msg } = useRef()
    const { person } = useReactive()
    setTimeout(() = > {
      person.name = 'ying zheng'
      person.age = 1000
      msg.value = 'update ... '
    }, 5000)
    watch([() = > person.name, () = > person.age, msg], ([foo, bar, msg], [prevFoo, prevBar, prevMsg]) = > {
      console.log(foo, bar, prevFoo, prevBar, msg, prevMsg)
    })
    return {
    }
  }
}
</script>
Copy the code

New life cycle

The new lifecycle optimizes the naming conventions and makes them easier to identify.

Life cycle name role
setup As a lifecycle for initializing a component, it acts like a combination of created and beforeCreated
onBeforeMount Compare the beforeMount life cycle of 2.x before mounting the DOM
onMounted The mounted declaration of 2.x is now accessible to the DOM
onBeforeUpdate Compare 2.xbeforeUpdate, the component generates hooks before updates
onUpdated Compare 2. Xupdated, the hook when the component is updated
onBeforeUnmount Compare 2. XbeforeDestroy, the hook before the component unloads
onUnmounted 2. Xdestroyed, component unmounts destroyed hooks

A series of new hooks are preceded by the on modifier as an annotation. At the same time, the state is also divided into mount, update, uninstall three stages. The change is not very big, for those of you who belong to the life cycle, it is just to get familiar with the use of the new API. There is not much consumption of learning.

import { reactive, watch, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue';
import { useRef, useReactive } from './hooks/useMod';

export default {
  name: 'Home'.props: {},
  setup (props, context) {
    / / get the MSG
    const { msg, updateMsg } = useRef()
    / / for the person
    const { person, updatePerson } = useReactive()
    
    onBeforeMount(() = > {
      console.log('onBeforeMount')
    })
    onMounted(() = > {
      console.log('mounted! ')
    })
    onBeforeUpdate(() = > {
      console.log('onBeforeUpdate')
    })
    onUpdated(() = > {
      console.log('updated! ')
    }) 
    onUnmounted(() = > {
      console.log('unmounted! ')})Copy the code

New dependency injection

The new dependency injection feature is very powerful. In the old version, provide and Inject played very low-key roles and were in the category of passer-by. However, in Vue3, there is a taste of diaosi attacking gao Fu Shuai. Enhanced communication makes it easier for developers to make certain plug-in injections. Even to some extent, they are just a knife for multi-functional features of the plug-in, developers can reasonably go to the development of Plugin, there are more choices.

The new Ref DOM

In older versions, this.$refs can get the values of all ref attributes mounted on the current node. In fact, this response to developer perception is problematic. So in this.refs, we don’t really know what the good perception is in this.refs, and most of the time I’m wondering if I got my refDOM. In the Composition API, all the refs in the interface are generated by the ref response that the user actively exposes, so that the behavior exposed by a Vue is transformed into the developer’s own behavior. It’s essentially changed. With dependency injection, you can retrieve the node REF property under the child node to retrieve what is exposed in the setup ‘of the child component binding ref. Do something “proactive.”

<template>
  <p ref="title"></p>
</template>

<script lang="ts">
import { ref, onMounted } from 'vue'

export default {
  name: 'Home'.props: {},
  setup () {
    const title = ref(null)
    onMounted(() = > {
      console.log(title)
    })
    return {
      title
    }
  }
}
</script>
Copy the code

nextTick

In Vue2.0, we used this.$nextTick to determine if the template DOM is currently mounted. In Vue3.0, nextTick split out a separate API for everyone to use, so that when you don’t use it, It is also shaken off by Tree to avoid unnecessary apis in your pages.

<script lang="ts">
import { nextTick } from 'vue'

export default {
  name: 'Home'.props: {},
  setup() {
    nextTick(() = > {
      console.log('DOM is mounted')
    })
  }
}
</script>
Copy the code

The latter

The introductory section is really shallow. The Composition API does a lot to get users to transition to the new version. There are no major changes to the API syntax, just a few ways to do it. Like function and arrow functions. They have different forms, but they’re still essentially a function. All changes are inseparable from it, so those who have some basic knowledge are advised to directly read the official document, which introduces most of the updated content. If you have a general idea of the impression concept after reading this article, you will find it very quick to get started by looking closely at the official compositionAPI documentation.

In the advanced part, the new instructions, logical split, combined V-model, and some advanced features will be explained step by step. Recently because of resignation, so part of the energy on the review of the book. The update is a bit slow. I also hope that if the article is useful to you, give me a little finger like it.

Some basic syntax of Vue3 is an essay, it is recommended to read after the official documentation, seamless, Vue3 syntax is not difficult, just need to be converted from the previous programming way.