⏳ preface

This is the 24th day of my participation in Gwen Challenge

I wrote two articles about the new features of VUE3, but… On Monday, I recently got several advanced new features, such as watch for VUe2 and Why watchEffect is used for VUe3. Also why VUe3 is faster than VUe2, why Vite starts up very quickly, and the major changes vue3 makes to the global registration API.

Learn about a wave of new vuE3 features 📷

📗 Watch and watchEffect

1. Differences between Watch and watchEffect

We often use Watch to monitor data in VUE2. But now Vu3 uses watchEffect for data monitoring. These two have the following specific differences:

  • You can listen in on bothdataAttribute change;
  • watchNeed to beSpecify which properties to listen for;
  • whilewatchEffectBased on its properties,Automatic monitoringThe change.

2. Take an example

(1) Wtach listens

We use watch to listen to data. The specific code is as follows:

<template>
    <! -- <p>watch vs watchEffect</p> -->
    <p>{{numberRef}}</p>
    <p>{{name}} {{age}}</p>
</template>

<script>
import { reactive, ref, toRefs, watch, watchEffect } from 'vue'

export default {
    name: 'Watch'.setup() {
        const numberRef = ref(100)
        const state = reactive({
            name: 'monday'.age: 18
        })
        
        watch(numberRef, (newNumber, oldNumber) = > {
            console.log('ref watch', newNumber, oldNumber)
        }
         , {
             immediate: true // Listen before initialization, optional})setTimeout(() = > {
            numberRef.value = 200
        }, 1500)

        watch(
            // The first argument determines which attribute to listen for
            () = > state.age,

            // The second argument, callback function
            (newAge, oldAge) = > {
                console.log('state watch', newAge, oldAge)
            },

            // The third parameter, the configuration item
             {
                 immediate: true.// Listen before initialization, optional
                 // deep: true // deep listening})setTimeout(() = > {
            state.age = 25
        }, 1500)
        setTimeout(() = > {
            state.name = 'mondayLab'
        }, 3000)

        return{ numberRef, ... toRefs(state) } } }</script>
Copy the code

The browser displays the following information:

If you want to be listened on initialization, you need to add the third optional parameter, immediate:true. So, if we want to listen for multiple properties, we have to write multiple watches, which is a bit of a hassle. So vue3 introduced the watchEffect to solve these problems.

(2) watchEffect monitor

We use watchEffect to listen for data. The specific code is as follows:

<template>
    <! -- <p>watch vs watchEffect</p> -->
    <p>{{numberRef}}</p>
    <p>{{name}} {{age}}</p>
</template>

<script>
import { reactive, ref, toRefs, watch, watchEffect } from 'vue'

export default {
    name: 'Watch'.setup() {
        const numberRef = ref(100)
        const state = reactive({
            name: 'monday'.age: 18
        })

        watchEffect(() = > {
            // The initialization must be performed first (collect data to listen on)
            console.log('hello watchEffect')
            console.log('numberRef', numberRef.value)
            console.log('state.age', state.age)
            console.log('state.name', state.name)
        })

        setTimeout(() = > {
            numberRef.value = 2000
        }, 1000)

        setTimeout(() = > {
            state.age = 25
        }, 1500)
        
        setTimeout(() = > {
            state.name = 'mondayLab'
        }, 3000)

        return{ numberRef, ... toRefs(state) } } }</script>
Copy the code

The browser displays the following information:

As you can see from the figure above, watchEffect can listen for three properties at once with just one listen. At the same time, it is worth noting that watchEffect needs to be initialized, and it must be initialized once to collect the data to listen on. So, the first set of data that the console prints is the data at initialization.

After the first collection it listens for these three properties, and after that, these three properties have responsivity accordingly. The corresponding three timers print out three more sets of data, so there are four sets of data.

📘setup How to obtain a component instance

(1) Why do I need to get component instances

When I first heard this concept, I was actually a little confused. Why use Setup to get an instance of a component? This is a “this” problem.

In VUe2, the Options API could use this to get an instance of a component, but this is now deprecated in vue3. This is not available in setup and other Composition apis, but it provides a getCurrentInstance to get the current instance.

(2) Take an example

Let’s start by using the Options API to get an instance. The specific code is as follows:

<template>
    <p>get instance</p>
</template>

<script>
import { onMounted, getCurrentInstance } from 'vue'

export default {
    name: 'GetInstance'.data() {
        return {
            x: 1.y: 2}},mounted() {
        console.log('this2'.this)
        console.log('x'.this.x, 'y'.this.y)
    }
}
</script>
Copy the code

The browser displays the following information:

As expected, with the Options API, specific instances can be called as expected.


Let’s use the Composition API to see if we can call it. The specific code is as follows:

<template>
    <p>get instance</p>
</template>

<script>
import { onMounted, getCurrentInstance } from 'vue'

export default {
    name: 'GetInstance'.data() {
        return {
            x: 1.y: 2}},setup() {
        // Cannot get this instance
        console.log('this1'.this)

        const instance = getCurrentInstance()
        console.log('instance', instance)

        onMounted(() = > {
            // Cannot get this instance
            console.log('this in onMounted'.this)
            // Get this instance with getCurrentInstance
            console.log('x', instance.data.x)
        })
    }
}
</script>
Copy the code

The browser displays the following information:

As you can see from the figure above, there is no way to get component instances using the Composition API. The getCurrentInstance method is used to get the current component instance.

Why is 📒 Vue3 faster than Vue2

Once when I was reading my book, I found a question: why is Vue3 faster than Vue2? At that time I also quite feel suspicious of, at that time my in the mind 🤯 : vue3’s appearance is not because better just appear? If it’s not better, can it be worse?

It turns out that… I’m out of my depth. Vue3 is faster than Vue2 in the following 6 aspects:

  • The Proxy response type
  • PatchFlag
  • hoistStatic
  • cacheHandler
  • SSR optimization
  • tree-shaking

Let’s take a look at it 🙋

1. Proxy responsiveness

Vue3 implements reactive proxies faster than Object. DefineProperty in VUe2. The specific reasons can be referred to another article of mine, which is not covered here.

2, PatchFlag

(1) What is PatchFlag

  • Dynamic nodes are used to mark templates when they are compiled.
  • Marks, divided intoDifferent types, such asTEXTPROPS; Some are direct accesstext, and some are modifiedprops
  • diffWhen we compare algorithms, we can distinguishStatic node, as well asDifferent types of dynamic nodes. The important thing to note here is,patchflagNot specificallydiffThe algorithm does optimization, but makes some changes and marks on the input to achieve the correctdiffOptimization of the algorithm.

(2) For example 🌰

We’ve demonstrated the patchFlag online, but the site is vue-template-explorer.net lify.app/, and people can keep up the quality of the response. ~

The specific use mode is shown in the figure below:

Next, we will demonstrate patchFlag. At this time, options on the right will not be selected. We enter the following code in the left box:

<div id="app">
  <span>hello vue3</span>
  <span>{{msg}}</span>
  <span :class="name">monday</span>
  <span :id="name">monday</span>
  <span :id="name">{{mag}}</span>
  <span :id="name" :msg="msg">monday</span>
</div>
Copy the code

The box on the right is displayed as follows:

import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("span".null."hello vue3"),
    _createVNode("span".null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createVNode("span", { class: _ctx.name }, "monday".2 /* CLASS */),
    _createVNode("span", { id: _ctx.name }, "monday".8 /* PROPS */["id"]),
    _createVNode("span", { id: _ctx.name }, _toDisplayString(_ctx.mag), 9 /* TEXT, PROPS */["id"]),
    _createVNode("span", {
      id: _ctx.name,
      msg: _ctx.msg
    }, "monday".8 /* PROPS */["id"."msg"]]))}// Check the console for the AST
Copy the code

As you can see, all are dynamic nodes except the first one, which is static. When the template is compiled, the corresponding number appears in the last edge, which is the tag. Vue3 can optimize the diff algorithm by marking each dynamic node digitally.

3, hoistStatic

(1) What is hoistStatic

  • The static node definition is promoted to the parent scope and cached.
  • Multiple adjacent static nodes are merged;
  • Typical space for time optimization strategy.

(2) For example 🌰

We’ll do a demo using an online site as well. At this point we enter the following code in the left border:

<div id="app">
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>{{msg}}</span>
</div>
Copy the code

The box on the right is displayed as follows:

import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

const _hoisted_1 = { id: "app" }
const _hoisted_2 = /*#__PURE__*/_createVNode("span".null."monday", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("span".null."monday", -1 /* HOISTED */)
const _hoisted_4 = /*#__PURE__*/_createVNode("span".null."monday", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _hoisted_4,
    _createVNode("span".null, _toDisplayString(_ctx.msg), 1 /* TEXT */)))}// Check the console for the AST
Copy the code

As you can see from the above code, VUe3 defines a parent node outside of each static node. It looks a little bit more redundant, because there are still fewer nodes.


Now let’s demonstrate more nodes, and select hoistStatic for options on the right. We enter the following code in the left border:

<div id="app">
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>{{msg}}</span>
</div>
Copy the code

The box on the right is displayed as follows:

import { createVNode as _createVNode, toDisplayString as _toDisplayString, createStaticVNode as _createStaticVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"

const _hoisted_1 = { id: "app" }
const _hoisted_2 = /*#__PURE__*/_createStaticVNode("mondaymondaymondaymondaymondaymondaymondaymondaymondaymonday".10)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", _hoisted_1, [
    _hoisted_2,
    _createVNode("span".null, _toDisplayString(_ctx.msg), 1 /* TEXT */)))}// Check the console for the AST
Copy the code

At this point, you can see that vue3 has surrounded all the static nodes into a parent node, just like vue3 said to its parent, how about this, I help you make a set of static nodes, help you define everything together.

4, cacheHandler

(1) What is cacheHandler

  • cacheHandlerRefers toCache eventThe meaning of.

(2) For example 🌰

We are also using an online site for a demonstration, where the options on the right select cacheHandler. We enter the following code in the left border:

<div id="app">
  <span @click="clickHandler">
    monday
  </span>
</div>
Copy the code

The box on the right is displayed as follows:

import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("span", {
      onClick: _cache[1] || (_cache[1] = (. args) = >(_ctx.clickHandler && _ctx.clickHandler(... args))) }," monday ")))}// Check the console for the AST
Copy the code

To observe the code onClick: _cache [1] | | (_cache [1] = (… args) => (_ctx.clickHandler && _ctx.clickHandler(… Args))) you can see that VUe3 will cache click events. This line of code means that it takes _cache[1] when there is a value for _cache[1], and defines a function for _cache[1] if there is none.

5. SSR optimization

(1) What is SSR optimization

  • Static nodes will output directly, bypassingvdom
  • If it’s a dynamic node, you still need to render it dynamically.

(2) For example 🌰

We also use the online website to make a demonstration, at this time, the options on the right choose SSR. We enter the following code in the left border:

<div id="app">
  <span @click="clickHandler">
    monday
  </span>
</div>
Copy the code

The box on the right is displayed as follows:

import { mergeProps as _mergeProps } from "vue"
import { ssrRenderAttrs as _ssrRenderAttrs, ssrInterpolate as _ssrInterpolate } from "@vue/server-renderer"

export function ssrRender(_ctx, _push, _parent, _attrs, $props, $setup, $data, $options) {
  const _cssVars = { style: { color: _ctx.color }}
  _push(`<div${
    _ssrRenderAttrs(_mergeProps({ id: "app" }, _attrs, _cssVars))
  }><span>monday</span><span>monday</span><span>monday</span><span>${ _ssrInterpolate(_ctx.msg) }</span></div>`)}// Check the console for the AST
Copy the code

It can be found from the above code that when using SSR for template compilation, static nodes will directly output, directly bypassing VDOM. If it is a dynamic node, dynamic rendering is still required.

6, tree – shaking

(1) What is tree-shaking

  • At compile time, depending on the situation, introduce differentAPI

(2) For example 🌰

Also use the online site to do a demonstration, this time the options on the right do not select. Enter the following code for the left border:

<div id="app">
  <span>monday</span>
  <span>monday</span>
  <span>monday</span>
  <span>{{msg}}</span>
</div>
Copy the code

The first line of the right box appears as follows:

import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
Copy the code

Let’s do another example. We also enter the following code in the left border:

<div id="app">
  <span :id="msg"></span>
  <input v-model="msg">
</div>
Copy the code

The first line of the right box appears as follows:

import { createVNode as _createVNode, vModelText as _vModelText, withDirectives as _withDirectives, openBlock as _openBlock, createBlock as _createBlock } from "vue"
Copy the code

As you can see, vue3 doesn’t introduce a lot of apis at compile time. Instead, it introduces what we need, what we want, and what we don’t want. This optimizes a lot of performance in a way.

Four, 📚Vite why start very fast

The first time I saw Vite was in the official documentation of VUe3. The official documentation said: Vite is a Web development build tool that can achieve lightning cold server startup due to its use of native ES module import method. You can use Vite to quickly build Vue projects by running the corresponding commands in the terminal.

What is a Vite

  • viteIt’s a front endPackaging tools, it isvueA project initiated by the author;
  • viteWith the help ofvueThe influence, rapid development, andwebpackThere is a certain competitive relationship;
  • Advantage:viteMake the programNo packaging is required in a development environmentAnd start very fast.

2. Why does Vite start fast?

Use ES6 Module in development environment, no packaging, very fast;

Using rollup packaging in a production environment is not much faster.

3, ES Module demonstration

(1) Basic use

In VUe2, when we load a project file, we need to convert it to ES5 first, and then go through some column packaging before we can load the project page. In VUE3, this is not done in the production environment, but in the development environment, through the ES6 Module way, no packaging, very fast.

Let’s look at how the ES Module in the demo is used in the browser.

(2) Application of ES Module in browser

1) Basic demo

<! DOCTYPEhtml>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>ES Module demo</title>
</head>
<body>
    <p>Basic demo</p>

    <script type="module">
        import plus from './src/plus.js'

        const res = add(1.2)
        console.log('add res', res)
    </script>

    <script type="module">
        import { plus, multi } from './src/math.js'
    </script>
</body>
</html>
Copy the code

We set type=”module” under the

2) Introduce external chain

<! DOCTYPEhtml>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>ES Module demo</title>
</head>
<body>
    <p>Outside the chain</p>

    <script type="module" src="./src/index.js"></script>
</body>
</html>
Copy the code

It is also possible to import external JS files directly via SRC.

3) Remote reference

<! DOCTYPEhtml>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>ES Module demo</title>
</head>
<body>
    <p>Remote reference</p>

    <script type="module">
        import { createStore } from 'https://unpkg.com/redux@latest/es/redux.mjs'
        console.log('createStore', createStore)
    </script>
</body>
</html>
Copy the code

It can also be directly imported to the URL on the CDN, that is, remote reference.

4) Dynamic introduction

<! DOCTYPEhtml>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>ES Module demo</title>
</head>
<body>
    <p>Dynamic introduction</p>
    <button id="btn1">load1</button>
    <button id="btn2">load2</button>

    <script type="module">
        document.getElementById('btn1').addEventListener('click'.async() = > {const add = await import('./src/add.js')
            const res = add.default(1.2)
            console.log('add res', res)
        })
        document.getElementById('btn2').addEventListener('click'.async() = > {const { add, multi } = await import('./src/math.js')
            console.log('add res', add(10.20))
            console.log('multi res', multi(10.20))})</script>
</body>
</html>
Copy the code

For example, if we want to bind two buttons to two events and have them import two different JS files, we can import them as needed in the arrow function after the click.

5. 📙 global API modification

With Vite out of the way, let’s move on to one of vuE3’s major changes, the global API. Look at the bottom.

1. Vue2 global API

In Vue2, global apis often encounter the following problems:

  • In unit testing, global configuration can easily contaminate the global environment.
  • In differentappsTo share a copy with different configurationsVueObjects also become very difficult.

Vue2 entry file:

import Vue from 'vue'
import App from './App.vue'

Vue.config.ignoredElements = [/^app-/]
Vue.use(/ *... * /)
Vue.mixin(/ *... * /)
Vue.component(/ *... * /)
Vue.directive(/ *... * /)

Vue.prototype.customProperty = () = {}

new Vue({
    render: h= > h(App)
}).$mount('#app')
Copy the code

Vue3 global API

(1) New writing method of Vue3

Therefore, in order to solve the problem of Vue2, Vue3 introduced a new writing method. The specific code is as follows:

New version of Vue3:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.isCustomElement = tag= >
tag.startsWith('app-')
app.use(/ *... * /)
app.mixin(/ *... * /)
app.component(/ *... * /)
app.directive(/ *... * /)

app.config.globalProperties.customProperty = () = {}

app.mount('#app')
Copy the code

(2) Common configurations are updated

1) Global configuration: vue. config->app.config

  • The config. ProductionTip to be deleted
  • Config. ignoredElements renamed config.isCustomElement

2) Global registration class API

  • Vue.component -> app.component
  • Vue.directive -> app.directive

3) Behavior extension class API

  • Vue.mixin -> app.mixin
  • Vue.use -> app.use

Vi. 📮 Conclusion

Here, say it! As you learn, understand the difference between Watch and watchEffect, and learn how Setup gets component instances, which is all about this.

Finally, why Vue3 is faster than Vue2, involving 6 performance optimization methods, learn to spare power, as far as possible with the online site to demonstrate a wave. Following in the footsteps of vue3, vite has become a tool used by many developers in their development environments. There are also changes Vue3 makes to the global registration API to address various issues such as global contamination.

This is the end of vuE3’s advanced features. Hope to help everyone!

  • Pay attention to the public number Monday laboratory, the first time to pay attention to learning dry goods, more interesting columns for you to unlock ~
  • If this article is useful to you, remember to click three times before going oh ~
  • See you next time! 🥂 🥂 🥂