One, foreword

It’s been a year since vuE3 was released. Today, LET’s talk about vuE2 and VUE3.

Before we do that, a few questions? You can listen to my share with these two questions

  1. It goes without saying that the birth of VUE3 is definitely to solve the problems existing in VUE2. Then what problems have been solved?
  2. What are the performance improvements of VUE3 compared with VUE2?

Ii. Differences between VUE2 and VUe3:

Vue2 is implemented based on object.defineProperty, with initialization data in data and business logic processing (computed, Methods, watch) and various lifecycle functions.

Disadvantages:

  1. Unable to listen for added and removed properties
  2. Unable to monitor array and object changes
  3. Business logic is distributed in Data, computed, methods, Watch and various life cycle functions, and the code is weak and not easy to read

Vue3 is based on a Proxy implementation that puts all the business logic in a setup function.

Advantages:

  1. Solved the problem of VUE2
  2. The diFF algorithm uses static marking, which greatly improves the efficiency of VUE execution
  3. Separation of concerns solves the problem of code redundancy in a single file (we’ll focus on this below)
  4. Static ascension
  5. Event listener cache
  6. Better support for TS
  7. High cohesion, low coupling
<script>
import { ref,defineComponent } from "vue";
 
export default defineComponent({
    setup() {
        const router = useRouter();
        const serviceName = ref("");
        let serviceData = ref<Array<IRecord>>([]);
        // Get a list of service providers
        const getServiceList = () = > {
            let data = {
            name: serviceName? .value, }; serviceList(data).then(res= > {
            if (res.code === 0) { serviceData.value = res.data.list; }}); };/ / add
        const addEvent = () = > {
            router.push({
            path: "service-add"
            });
        };
        / / edit
        const editEvent = (record: IRecord & { id: number }) = > {
            router.push(`service-edit/${record.id}`);
        };
        / / search
        const searchEvent = () = > {
            getServiceList();
        };
        onMounted(() = > {
            // Get a list of service providers
            getServiceList();
        });
        return {
            serviceData,
            serviceColumns,
            serviceName,
            / / event
            searchEvent,
            addEvent,
            editEvent
        };
    }
})
</script>
Copy the code

New features of VUE3

Composition API

The composite API is essentially a setup function that puts the relevant business logic together to solve the previous vue2 code fragmentation problem, and finally returns the required variables (reactive and non-reactive) and functions.

import { ref,defineComponent } from 'vue'
 
export default defineComponent({
    setup() {
      const count = ref(0)
      const handleClick = () = >{}return {
        count,
        handleClick
      }
    }
})
Copy the code

The simplest setup consists of defined data and functions that are eventually returned in a return for use in templates. Here’s what setup consists of:

1, ref() response function

import { ref } from 'vue'
const count = ref(0)
Copy the code

Ref takes a parameter and returns an object with a value attribute that can be used to modify the corresponding value.

import { ref,defineComponent } from 'vue'
 
export default defineComponent({
    setup() {
      const count = ref(0)
      console.log(count.value); / / 0
      // Change the value of value
      count.value++;
      console.log(count.value); / / 1}})Copy the code

Question:

After ref takes a parameter, why does it return an object?

A ref converts the incoming value and object into a Proxy object. Since Proxy only supports reference objects, the value object is converted to {value: “value “} and then converted to a Proxy object. In this case, the value value can be monitored.

Why use ref?

It is the same as the data defined in VUe2, so that the vUE base layer knows that it is a reactive variable.

Reactive Returns a reactive copy of the object

Const person = reactive({name: "reactive"})Copy the code

The person returned is a reactive object that is not equal to the original object, so it is recommended to use only the proxy object.

import { reactive,defineComponent } from 'vue'
 
export default defineComponent({
    setup() {
      const obj = {
        name: "The world"
      }
      const person = reactive(obj)
 
      console.log(obj === person) //false
 
      / / modify the value
      setTimeout(() = >{
        person.name = "Xiao";
        person.age = 18;
      },1000)}})Copy the code

How to use lifecycle functions in setup

The composite API and the optional AP declare the same period function, except that the composite API is prefixed with “on” and has the following life cycle function

Vue2 Vue3
beforeCreate
created
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeMount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTirggered
activated onActivated
deactivated onDeactivated
import { onMounted,defineComponent } from "vue";

export default defineComponent({
    setup() {
      onMounted(() = >{
        console.log("onMounted"); })}})Copy the code

4

Three parameters are accepted:

  • The reactive reference you want to listen for
  • A callback
  • Optional configuration options
import { ref,watch,defineComponent } from "vue";
 
export default defineComponent({
    setup() {
    const num = ref(0);
    watch(num,(newNum,oldNum) = >{
      console.log("newNum",newNum); / / 666
      console.log("oldNum",oldNum); / / 0
    })
    setTimeout(() = >{
      num.value = Awesome!;
    },1000)}})Copy the code

5, the computed

import { ref,computed,defineComponent } from "vue";
 
export default defineComponent({
    setup() {
      const str = ref("Hello");
      const splitVal = computed(() = >{
        return str.value.split("");
      })
      console.log("splitVal.value",splitVal.value); //['H', 'e', 'l', 'l', 'o']}})Copy the code

6. Setup functions

Parameters:

  • props
  • context

Props are reactive and updated when a new prop is passed in.

/ / the parent component<test-setup title="Welcome to Beijing"></test-setup>
Copy the code
/ / child component
export default defineComponent({
    props: {
        title: String
    },
    setup(props,context) {
        console.log("--- setup ---");
        console.log("props",props); //Proxy {title: 'Beijing welcome you '}
        console.log("context",context); }})Copy the code

Note: Because props are reactive, it cannot be deconstructed with ES6, which eliminates the reactive behavior of prop.

Refs can be used in the setup function if deconstruction is required.

// Lost responsiveness
const { message } = props;
console.log("message",message); // Parent component information
 
const { title } = toRefs(props);
console.log("title",title); //ObjectRefImpl {_object: Proxy, _key: 'title', __v_isRef: true}
Copy the code

If title is an optional prop, the prop passed in May not have this property, in which case toRefs does not create a ref and needs to use toRef instead.

import { toRef,defineComponent } from "vue";
 
export default defineComponent({
  setup() {
    const otherMessage = toRef(props,"otherMessage");
    console.log("otherMessage",otherMessage.value); //undefined}})Copy the code

Context is a plain JS object that exposes three properties of the component

  • Attrs properties
  • Slots slot
  • Emit trigger event

Context objects are not reactive objects and can therefore be deconstructed

import { defineComponent } from "vue";
 
export default defineComponent({
  setup(props,{ attrs, slots, emit}) {
    console.log("attrs",attrs);
    console.log("slots",slots);
    console.log("emit",emit); }})Copy the code

7. Difference between REF and Reactive:

Both ref and Reactive can be variable responsive, with REF primarily used for individual variables and Reactive primarily used for form objects.

Variables after ref are accessed through a. Value value, whereas reactive can be accessed directly through [data].[property].

4. Separation of concerns

<a-form-item class="width200">
  <a-select
            placeholder="Please select applets"
            v-model:value="formState.applet"
            :options="appletData"
            @change="appletHandle"
            >
  </a-select>
</a-form-item>
Copy the code
import useAppletData from "./market-data-helper/useAppletData";
 
export default defineComponent({
  setup() {
    const { appletData } = useAppletData();
    return {
      appletData
    }
  }
})
Copy the code

The relevant business logic code is separated

The useappletdata. ts file is used to separate the requested data from the dropdown, return the requested data, and use it in the list page above.

//useAppletData.ts
import { ref, onMounted } from "vue";
import { appletList } from ".. /.. /.. /.. /api/common";
 
interface IOptions {
  label: string;
  value: string;
}
const appletDataOptions = [{ label: "All applets".value: "" }];
export default function useAppletData() {
  const appletData = ref<Array<IOptions>>(appletDataOptions);
  const getAppletList = async() = > {let data = {
      page: 1.pageSize: 999999
    };
    let res = await appletList(data);
    if (res.code === 0) { appletData.value = res; }};return {
    appletData
  };
}
Copy the code

This greatly improves reading speed and eliminates redundancy in code.

Vue -router

In VUe2 we use this.$router as a route jump, but in VUe3 we don’t have this, so we use it like this:

import { defineComponent } from "vue";
import { useRouter } from "vue-router";
 
export default defineComponent({
  const count = ref(0);
  const router = useRouter();
  const handleClick = () = > {
    router.push({ name: "AddApplet" });
  }
  return {
    count,
    handleClick
  }
})
Copy the code

Use in vuex

import { useStore } from 'vuex'
 
export default defineComponent({
    setup() {
    const store = useStore()
    const count = store.state.count;
    return {
        count,
    }
  }
})
Copy the code

Support for TypeScript

Constraints apply from the definition of the list’s initial data to the request interface to the returned data.

List:

// List defined data
interfaceApplet { id? :number;
  code: string;
  createAt: String.logo: string.merchantName: string.name: string;
  serviceName: string;
  tag: string;
  tagId: string;
}
 
const appletData = ref<Array<Applet>>([]);
Copy the code
// Returns the value definition in the value data
interface AppletListResponse {
  count: number;
  list: Array<Applet>;
  page: number | string;
  pageSize: number | string;
}
 
// The value definition returned by the list
interface AppletListRes {
  code: number;
  msg: string;
  data: AppletListResponse;
}
 
appletList(params).then((res: AppletListRes) = > {
  if (res.code === 0) { appletData.value = res.data.list; total.value = res.data.count; }});Copy the code
/ / parameters
interface AppletParams {
  page: number | string;
  pageSize: number | string; name? :string; storeName? :string; serviceName? :string; tag? :string;
}
 
// Interface request
export const appletList = (params: AppletParams): Promise<AppletListRes> => {
  return Http.get("/applet/list", params);
};
Copy the code

Script setup

As you may have noticed, even though we can do separation of concerns code, the setup function still looks like a lot of code. Is there a way to make setup shorter? The script Setup syntax for VUE3 3.2 has been released to the public, and it is very sweet to use.

1, Setup basic usage:

It’s easy to use, just add the setup keyword to the script tag.

<script setup></script>
Copy the code

2. Automatic component registration

In Script Setup, imported components do not need to be registered with Components.

<script setup>
    import HelloWorld from './components/HelloWorld.vue'
</script>
 
<template>
  <HelloWorld msg="Hello Vue 3 + Vite" />
</template>
Copy the code

3. Use of component core API

(1) use defineProps

DefineProps specifies the current props type to get the props object of the context.

<script setup>
import { ref } from 'vue'
const props = defineProps({
  msg: String
})
const count = ref(0)
</script>
Copy the code

(2) use emits

The parent component:

<script setup>
import HelloWorld from './components/HelloWorld.vue'
 
const handle = (val) = > {
  console.log(val); / / the world
}
</script>
 
<template>
  <HelloWorld
    msg="Hello Vue 3 + Vite"
    @handle="handle"
  />
</template>
Copy the code
<script setup>
import {
  defineEmits
} from 'vue'
 
const emits = defineEmits("handle");
const handleClick = () = > {
  emits("handle"."The world")
}
</script>
 
<template>
  <button type="button" @click="handleClick">Click on the</button>
</template>
Copy the code

(3) Get slots and attrs

UseAttrs and useSlots are used to obtain slots and attrs, respectively.

<script setup>
    import { defineProps,useAttrs,useSlots } from 'vue'
    const attrs = useAttrs();
    const slots = useSlots();
</script>
Copy the code

(4) Attributes and methods do not need to return, directly use

In script Setup, variables and functions need to return to be used in the template.

<script setup>
  import { ref } from 'vue'
  const count = ref(0)
  const handleClick = () = > count.value++
</script>
 
<template>
  <button type="button" @click="handleClick">count is: {{ count }}</button>
</template>
Copy the code

Does that make it easier for you?

Finally, LET me summarize for you:

Vue3 has a lot of underlying and logical advantages. It uses Proxy instead of object.defineProperty, and resolves the limitations of vUE’s previous handling of arrays and objects. The performance of VUE was greatly improved by optimizing diff algorithm, static lift, and event listener cache.

In terms of usage, VUe3 uses composite API, which focuses on high cohesion and low coupling of code, instead of optional isolation (Data, Methods, Watch and Mounted). Separation of concerns improves readability when there is too much code. Finally, VUe3 recently used the Script Setup syntax sugar to make code more concise.