This article is I in the vUE official website and some other places to learn some of the v3 learning records and experience, if there is no understanding of the place welcome to correct.


1. Changes in data

In version V3, data is normalized to accept only functions that return Object, whereas in version V2, both functions return Object and Object are supported.

2. Mixin merger changes

In version v3, the merge of objects is an override, not a merge.

const mixinObject = {
  data(){
    return {
      user: {id:1.name:'jack'}}}}const CompA = {
  mixins: [mixinObject],
  data() {
    return {
      user: {
        id: 2}}}}/ / as a result
user: {
  id: 2
}

Copy the code

3. Remove $on, $off, $once methods

In version v2, $on, $off is used to implement the global event bus, and $once binding is used to listen for a custom event. In fact, these are not very much used in real projects. After version V3 is removed, some external libraries can be used to implement the relevant requirements. For example, mitt

4. The filter is deleted

V3 version removed filter, {{calcNum | filter}} will not support, authorities recommend the use of computed properties replace filters (well done ~).

Segments of 5.

V3 supports components that can have multiple root nodes, reducing node hierarchy depth. But it also wants developers to be clear about the semantics.

<template>
  <header></header>
  <main></main>
  <footer></footer>
</template>
Copy the code

6. Functional components

Before moving on to the v3 changes, let’s review the v2 version of functional components, which can be created in two ways: functional attribute and {functional: true}, respectively

/ / attribute
<template functional>
  <img :src="src" />
</template>
<script>.</script>


// Options
export default = {
  functional:true.props:{
      ...
  },
  render:function(createElement,context){.../ * * the context contains some parameters: props, slots, the parent, listeners, injections * * /}}Copy the code

There are two types of components in version V2: stateful components and functional components (stateless components). Compared to stateful components, functional components do not need to be instantiated, are stateless, have no lifecycle hooks, and are rendered much faster than stateful components. It is often applied to static display components with a single function to optimize performance. In addition, functional components have the ability to return multiple root nodes.

In VERSION V3, the performance difference between stateful and functional components has been greatly reduced and is almost negligible in most scenarios. So the only advantage of functional components is the ability to return multiple nodes at once, but this is often used less often and the components tend to be simpler. The syntax sugar is as follows:

// Create a function
import { h } from 'vue'

const DynamicHeading = (props, context) = > {
  // Context is an object containing ATTRs,slots, and emit
  return h(`h${props.level}`, context.attrs, context.slots)
}

DynamicHeading.props = ['level']

export default DynamicHeading


// Single-file component (SFC)
<template>
  <component
    v-bind:is="`h${$props.level}`"
    v-bind="$attrs"
  />
</template>

<script>
export default {
  props: ['level']}</script>
Copy the code

7. Global API adjustment

V3 version added a new global APIcreateApp, through the ES module introduced. The call to createApp returns an application instance that exposes the global API. This is a new Vue3 concept that addresses the ability to share resources (configurations, global components, directives, etc.) between different “apps”. Let’s compare the changes to creating applications for V3 and V2 respectively.

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

Vue.config.productionTip = false

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


/ / v3 created

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

var app = createApp(App);
app.mount('#app')
Copy the code

One way to share configuration between “apps” is factory mode:

import { createApp } from 'vue'
import App1 from './App1.vue'
import App2 from './App2.vue'

const createMyApp = options= > {
  const app = createApp(options)
  app.directive('focus' / *... * /)
  return app
}

createMyApp(App1).mount('#foo')
createMyApp(App2).mount('#bar')
Copy the code

V3 moves the API for changing Vue behavior globally from the original Vue constructor to the instance. The list below

Global API v2 Global API v3
Vue.config app.config
Vue.config.productionTip remove
Vue.config.ignoredElements app.config.ignoredElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use

In addition, there are global apis and internal components that have been refactored. For tree-shaking, it can only be imported as an ES module, meaning that components and interfaces that are not used in your application will not be packaged. The list of affected apis is as follows:

  • Vue.nextTick
  • Vue.observable (replace vue.reactive)
  • Vue.version
  • Vue.com compile (full build only)
  • Vue.set (compatible build only)
  • Vue.delete (build compatible only)
// Error
import Vue from 'vue'

Vue.nextTick(() = > {
  // Something related to the DOM
})


// Correct use
import { nextTick } from 'vue'

nextTick(() = > {
  // Something related to the DOM
})
Copy the code

8. Composite APIS

The highlight!!

This is a new concept in V3, vUE gives us some new apis, and these new apis are used in one place, and this place is vUE gives us a new place to do something from component initialization to destruction, which I think of as the hook function — Setup. In Setup, You can do all the things that you can do in vUE components, everything that you do in Created, Mounted, computed, Watch, Methods, you can do in Setup, and how do you do that, through these new apis that Vue provides. So what does this thing mainly solve? We all know that components are for the extraction of functionality and the reuse of code. This allowed us to go a long way in terms of flexibility and maintainability, but it wasn’t enough. When the logic inside a component was complex, we scattered the logic in created, Mounted, Methods, computed, and Watch, and the entire file was hundreds of lines of code. Trying to understand the logic can be a major headache for someone who hasn’t written the component. Setup solves this problem by putting all the logic together and processing it in the Setup. From now on, when you want to build a car, you don’t have to import parts from all over the world, you can do it in a Setup factory. Let’s take a look at Setup and the new apis in action. :

Setup

If you understand what I said above, then you should understand when I start by writing:

<template>
  <div class="demo">
  </div>
</template>
<script>
export default {
  name:"Demo".data(){
    return {}
  },
  setup () {
    console.log('run'); }}</script>

// Print run when running
Copy the code

Setup returns an object whose properties you can access elsewhere in the component.

Note: The component instance was not created when the Setup was performed, so there is no this in the Setup. It does, however, provide two reception parameters — props and context. You cannot access any other properties in the component from Setup.

// Call the Demo component
<Demo :name="'jac" a="1" b="2"></Demo>

/ / the Demo components
<template>
  <div class="demo">
  </div>
</template>
<script>
export default {
  name:"Demo".props: {name:String,},data(){
    return {}
  },
  setup (props,context) {
    console.log('props',props); // {name:jac}
    console.log('attrs', context.attrs); // {a:1,b:2}
    console.log('slots', context.slots); / / {}
    console.log('emit', context.emit); // function
    
    let shareProp = 'hallo,v3';
    
    // Return the two properties shareProp, changeProp
    return {
      shareProp
    }
  },
  mounted() {
    this.shareProp = 'changed'; }},</script>
Copy the code

The property in the data() option is responsive. That is because Vue created a dependency on the property in data() during component initialization. So when the property changes, the view automatically updates, and that’s the response. So how do you make it responsive?

ref & reactive

We can create reactive states by using ref reactive,reactive,

Reactive state. Reactive state. Reactive state. Reactive state. Reactive state. Reactive state. Reactive state. Reactive state. So what’s the difference between ref and reactive?

const refNum = ref(10);
const refObj = ref({
  name:'jac'.age:20
});
const reactiveNum = reactive(10);
const reactiveObj = reactive({
  name: 'jac'.age: 20
})
console.log('refNum',refNum);
console.log('refObj',refObj);
console.log('reactiveNum', reactiveNum);
console.log('reactiveObj', reactiveObj);
Copy the code

Here are the results:

When the ref is creating a complex data type, the interior is also created using reactive. So it is possible for a ref to create a response state for a complex data type, but it will be written differently in setup.

setup(){
  const refObj = ref({
    name:'jac'.age:20
  });
  const reactiveObj = reactive({
    name: 'jac'.age: 20
  })
  // Update in ref mode
  const changeRefObj = () = > {
    refObj.value.name="mac"
  }
  // Update the reactive mode
  const changeReactiveObj = () = > {
    reactiveObj.name = 'mac'
  }
  return{... }}Copy the code

Note: the values are wrapped by the ref. In Setup you need to use the variable.value to access and set the values. Objects exposed from Setup you can use this directly. Variable access.

<template>
  ...
</template>
<script>
import { ref,reactive } from 'vue';
export default{... setup (props,context) { ...let shareProp = ref('hallo,v2');
    let info = reactive({name:'jac'});
    const changeProp = () = >{
      shareProp.value = 'hallow,v3';
    }
    return{ shareProp, ... }},mounted() {
    console.log(this.shareProp)
  },
}
</script>
Copy the code

Friends can choose to use according to their own coding habits.

toRef & toRefs

Sometimes when we want to deconstruct variables from a complex responsive variable, our code might look like this:

<template>
  <button @click="changeObj">my name is {{info.name}}</button>
</template>
<script>
import { ref, provide, reactive } from 'vue';
export default {
  name: 'Demo'.setup(){
    const info = reactive({name:'jac'.sex:'male'.age:18});
    return {
      info
    }
  },
  methods: {changeObj(){
      let { name,sex } = this.info;
      name = 'make'
      // Views are not updated}}}</script>
Copy the code

In this case, we need to use toRef and toRefs to deconstruct them. ToRef is used to deconstruct the responsive variable of a single property. ToRefs is used to create responsive variables for all properties in the source object. Create our corresponding variables by deconstructing.

<template>
  <button @click="changeObj">my name is {{info.name}}</button>
</template>
<script>
import { ref, provide, reactive, toRef, toRefs} from 'vue';
export default {
  name: 'Demo'.setup(){
    const info = reactive({name:'jac'.sex:'male'.age:18});
    return {
      info
    }
  },
  methods: {changeObj(){
      // toRef
      // let name = toRef(this.info,'name'); // arg1: source object, arg2: attribute name
      // name.value = 'make'
		
      // toRefs  
      // let { name } = toRefs(this.info); // arg1: source object
      // name.value = 'make'
      
      // The view was refreshed successfully}}}</script>

Copy the code

Watch & Computed & Register life cycle hooks

In Setup we can also watch properties, create independent computed, and register various lifecycle hooks. Because the phases of Setup execution revolve around beforeCreate and Created, everything that was done in these two lifecycles can be handled in Setup.

<template>
  ...
</template>
<script>
import { ref, toRefs, watch, computed, onMounted } from 'vue';
export default {
  name:"Demo".props: {name:String,},... setup (props,context) {console.log('I execute first');
    // Create the props response variable with the toRefs method
    const { name: listenName } = toRefs(props);
    const count = ref(0);
    const changCount = () = >{
      count.value++;
    }
    const totalCount = computed(() = > {
      return 'Total number:${count.value}`
    })
    // Watch will listen for the listenName variable and trigger the callback method if the listenName variable changes
    watch(listenName,(newValue, oldValue) = >{
      console.log(listenName.value); 
    })
    onMounted(() = >{
      console.log('onMounted is also executed, and the output is as follows');
      console.log(count.value);
      changCount();
      console.log(totalCount.value)
    })
    return {
      count,
      changCount,
      totalCount,
    }
  },
  created() {
    console.log('Created executed');
  },
  mounted() {
    console.log('Mounted executed'); }},</script>

// The output is as follows:I first executed created and I executed onMounted, and the output is as follows0Total number of:1Mounted performedCopy the code

As you can see, the lifecycle hook functions registered in Setup are executed before those registered outside.

provide & inject

Provide and Inject are not commonly used in business scenarios, but are useful when writing plug-ins or component libraries. Provide and inject are used to provide properties in “ancestor” components and to inject properties in child components. How do you use that in setup?

// Provided in the Demo component
<template>
  <Test />
</template>
<script>
import { provide } from 'vue';
export default {
  name:"Demo",
  setup (props,context) {
    provide('name'.'jac')}},</script>

// Insert into the test component
<template>.</template>
<script>
import { inject } from 'vue';
export default {
  name:"Test",
  setup (props,context) {
    console.log(inject('name')); // jac}},</script>

Copy the code

This is the basic application of Setup, but you need to get a good feel for it and use it in a variety of scenarios to get a better idea of what it’s good for, like this code:

// a.js
import { ref, onMounted } from 'vue'
export default function doSomething(refName,fn){
  const a = ref(0);
  const b = ref(0);
  / /... .
  onMounted(() = > {
   fn();
  })

  return {
    a,
    b
  }
}

//b.js
import doSomething from './a.js';
setup(){
  const {a,b} = doSomething('box'.() = >{
    console.log('execution'); })}Copy the code

I literally an example, suppose you have a logic in multiple pages are needed, then we can pull away from the logic, which makes our code more concise, we can make a component reuse, not only in some business also can further improve code reuse, code can also focus on business, I believe that the quality for our development experience or code, It’s all very helpful.

9. v-model

Change the default value and trigger method of v-model in v3, value=>modelVale,input=>update. In a custom component, this allows us to set up multiple V-Models at the same time.

// Demo.vue
export default {
  name: "Demo".props: {
    title:String.label:String
  },
  methods: {
    titleEmit(value) {
      this.$emit('update:title', value)
    },
    labelEmit(value) {
      this.$emit('update:label', value)
    }
  },
}

/ / call the Demo. Vue
<Demo v-model:title="" v-model:label="" />
Copy the code

10. Typescript support

V3 recommends Typescript. Typescript not only supports the features of ES6, but also has type derivation, which can help you avoid many type errors during development. In a time of increasing front-end complexity, Typescript can support applications that are much more maintainable and extensible. Embrace change.

How do you create a Vue3 +typescript application?

1. Use vue – cli

Yarn global add@vue /cli@next # OR NPM install -g@vue /cli@next // Create yarn global add@vue /cli@next # OR NPM install -g@vue /cli@next // Create yarn global add@vue /cli@next # OR NPM install -g@vue /cli@next //Copy the code

2. Use Vite (personal recommendation, easy and easy)

yarn create vite-app my-vue-ts --template vue-ts
Copy the code

Pa! No!

In this section, we will take a brief look at some of the changes in V3 from the application level, without digging into the principles and implementation.

V3 a mirror 999 times card!