Vue3 combined with TS project development practice summary

An overview of the

Vue3 has been out for some time. In the team, we have also carried out a lot of business practices and had some thoughts of our own.

In general, Vue3 has made great progress both in the underlying principles and in the actual development of the business.

The API of Object. DefineProperty is replaced by proxy, which has better performance and solves the defects of vUE in handling objects and arrays. In diFF algorithm, static marking method is used, which greatly improves the efficiency of Vue execution.

In terms of usage, we changed from Options Api to Composition Api, and gradually abandoned the original isolated writing methods such as data, methods and computed in actual business. The Compositon Api, which is more focused, is about the integration of related businesses. At the same time, the Composition Api provides a separation of concerns to prevent overly heavy business logic, greatly improving the readability of our code.

Fully supported TypeScript, type validation is a quality assurance for future Vue3 projects, and it’s a trend – the future of the front end is TypeScript!

1, compositon Api

The essence of the Compositon Api is embodied in the code as a setup function that returns data that is used in the component’s template. The object of return, to some extent, represents the data property in vue2.

import { defineComponent, ref } from 'vue';
export default defineComponent({
    name: 'Gift'.setup() {
        const counter = ref(0);
        return {
            counter
        }
    }
})
Copy the code

For most beginners, the question is, can I define options APIS for data, computed, watch, methods, and so on?

I need to be clear that Vue3 is fully compatible with the options Api of Vue2, but it is more recommended to write our components in the way of setup conceptually. The reason is as follows: the existence of Vue3 itself is to solve the problem of Vue2, the problem of Vue2 is that the lack of convergence will lead to more and more bloated code! Setup allows data, method logic, and dependencies to be aggregated together for easier maintenance.

That is to say, we should try not to write separate data, computed, watch, methods and so on in the future. It is not that Vue3 does not support it, but that it goes against the concept of Vue3.

The components property, which is a child of a component, differs little between Vue2 and Vue3.

1. The difference between REF and Reactive?

In terms of functions, REF and Reactive are both capable of implementing responsive data.

On the grammatical level, the two are different. [data]. Value; Data defined by Reactive needs to be changed in the form of [data].[prpoerty].

const actTitle: Ref<string> = ref('Activity Name');

const actData = reactive({
    list: [].total: 0.curentPage: 1.pageSize: 10
});

actTitle.value = 'Activity Name 2';

actData.total = 100;
Copy the code

However, at the application level, there are still differences. Generally speaking, for a single common type of data, we use ref to define the response. Forms scenarios, in which a key:value object of a form is described, use Reactive; In some scenarios, a set of data in a module is usually defined by Reactive.

Do objects have to be defined using Reactive? In fact, not, can be, according to their own business scenarios, specific problems specific analysis! Ref stresses changes to the value of a data, and Reactive stresses changes to an attribute of a defined object.

2. Periodic function

Periodic functions, in Vue3, are used separately as follows:

import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
    name: 'Gift'.setup() {
        const counter = ref(0);
        onMounted(() = > {
            // Make a request for data
        })
        return {
            counter
        }
    }
})

Copy the code

3, store use

In Vue2, you can fetch this.$store directly, but in Vue3, there is no such thing as this.

import { useStore } from "vuex";
import { defineComponent, ref, computed } from 'vue';
export default defineComponent({
    name: 'Gift'.setup() {
        const counter = ref(0);
        const store = useStore();
        const storeData = computed(() = > store); // With computed, get the value of store.
        return {
            counter,
            storeData
        }
    }
})
Copy the code

4. Use the Router

Vue2 uses this.$router as a function to program the route, but Vue3 uses this:

import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { defineComponent, ref, computed } from 'vue';
export default defineComponent({
    name: 'Gift'.setup() {
        const counter = ref(0);
        const router = useRouter();
        const onClick = () = > {
            router.push({ name: "AddGift" });
        }
        return {
            counter,
            onClick
        }
    }
})
Copy the code

2. Separation of concerns

Separation of concerns can be divided into two meanings: the first meaning is that Vue3 setup itself puts the relevant data and processing logic together, which is a kind of aggregation of concerns, which makes it easier for us to look at the business code.

The second level of separation of concerns is that as setup becomes larger, we can extract relevant pieces of business from within setup.

import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { defineComponent, ref, computed } from 'vue';
import useMerchantList from './merchant.js';
export default defineComponent({
    name: 'Gift'.setup() {
        const counter = ref(0);
        const router = useRouter();
        const onClick = () = > {
            router.push({ name: "AddGift" });
        }
        // In this example, we separate out the related business of getting the merchant list. Merchant.ts below
        const {merchantList} = useMerchantList();
        return {
            counter,
            onClick,
            merchantList
        }
    }
})
Copy the code

merchant.ts

import { getMerchantlist } from "@/api/rights/gift";
import { ref, onMounted } from "vue";

export default function useMerchantList() :Record<string.any> {
  const merchantList = ref([]);
  const fetchMerchantList = async() = > {let res = awaitgetMerchantlist({}); merchantList.value = res? .data? .child; }; onMounted(fetchMerchantList);return {
    merchantList
  };
}
Copy the code

TypeScript support

This part of the content, to be precise, is the content of TS, but it is closely related to the development of Vue3 project, so to really use Vue3, we need to understand the use of TS.

In this section, HOWEVER, I will not cover the basic syntax of TS, but how to organize TS in a business scenario.

One of the core ideas for business development with TS is to focus on data structures and then develop pages based on them. The old model of front-end development was to write the page first and focus on the data later.

For example, to write a gift list page, we might define some of these interfaces. In summary, we need to focus on: the interface of the page data, the data type returned by the interface, the input parameter type of the interface, and so on.

// Each item in the gift creation, editing, and list will be of this data type.
interface IGiftItem {
  id: string | number;
  name: string;
  desc: string;
  [key: string] :any;
}

// Global corresponding type definition
// In general, we don't know what type an interface returns (null, object, array), so we use a stereotype to define an interface
interface IRes<T> {
    code: number;
    msg: string;
    data: T
}
// The interface returns a data type definition

interface IGiftInfo {
    list: Array<IGiftItem>;
    pageNum: number;
    pageSize: number;
    total: number;
}
Copy the code

In a common interface request, we typically use TS to define a data request, the data request type reQ, the data request type RES.

export const getGiftlist = (
  params: Record<string.any>
): Promise<IRes<IGiftInfo>> => {
  return Http.get("/apis/gift/list", params);
};
Copy the code