Some of the concepts

The Vue Composition API (VCA) is actually implemented to expose more explicitly the responsive system of Vue itself. This is not a function, but the API is exposed as a function. 3.0 Template compiles several times faster than handwritten JSX. – especially the rain creek

With traditional data, computed, watch, and methods, Vue2 uses Composition API (VCA) to organize code according to logical functions. A feature-specific API is put together.

Vue and React logic reuse means

So far,

Vue: Mixins, HOC, scope slot, Vue Composition API (VCA/ composite API).

React: Mixins, HOC, Render Props, Hook

We can see that both of them have a better and better growth history. I will not repeat the examples here. This paper focuses on VCA, which is more inclined to the concept of “combination”.

Vue3 in five dimensions

1. The framework

An example is to look at the VCA

In Vue, there is the concept of abstract encapsulation components, to solve the problem that the more modules on the page, the more bloated. But even for components encapsulation, at the time of application is more and more big, will find logic function point more and more of the page, the data computed/watch/the methods will be constantly into logical function, so will logic to pull away, reuse, that is the VCA.

Here’s a simple example:

We’re going to implement three pieces of logic

  1. Get the table data by ID
  2. Table data can be searched and filtered
  3. Add data to the table

Vue2 Options API processing

Some code has been omitted for the sake of quality, but it does not affect our understanding of the VCA

// Logic function (1)
const getTableDataApi = id= > {
  const mockData = {
    1: [{id: 11.name: "Zhang SAN 1 ' },
      { id: 12.name: 'li si 1' },
      { id: 13.name: 'fifty and 1'}].2: [{id: 21.name: 'Joe 2' },
      { id: 22.name: 'bill 2' },
      { id: 23.name: 'fifty and 2'}};return new Promise(resolve= > {
    setTimeout(() = > {
      resolve(mockData[id] || []);
    }, 1000);
  });
};

export default {
  name: 'VCADemo'.components: { Modal },
  data() {
    return {
      // Logic function (1)
      id: 1.table: [].// Logic function (2)
      search: ' '.// Logic function (3)
      modalShow: false.form: {
        id: ' '.name: ' '}}; },computed: {
    // Logic function (2)
    getTableDataBySearch() {
      return this.table.filter(item= > item.name.indexOf(this.search) ! = = -1); }},watch: {
    // Logic function (1)
    id: 'getTableData'
  },
  mounted() {
    // Logic function (1)
    this.getTableData();
  },
  methods: {
    // Logic function (1)
    async getTableData() {
      const res = await getTableDataApi(this.id);
      this.table = res;
    },
    // Logic function (3)
    handleAdd() {
      this.modalShow = true;
    },
    // Logic function (3)
    handlePost() {
      const { id, name } = this.form;
      this.table.push({ id, name });
      this.modalShow = false; }}};Copy the code

This is just a simple example of logic. If the project is complex, the logic increases. When a logical change is involved, we may need to modify the same function points in different locations, increasing maintenance costs.

Vue3 Composion API processing

Let’s focus on the logic, pull away from the logic, and look at the code structure of the body first

import useTable from './composables/useTable';
import useSearch from './composables/useSearch';
import useAdd from './composables/useAdd';

export default defineComponent({
  name: 'VCADemo'.components: { Modal },
  setup() {
    // Logic function (1)
    const { id, table, getTable } = useTable(id);
    // Logic function (2)
    const { search, getTableBySearch } = useSearch(table);
    // Logic function (3)
    const { modalShow, form, handleAdd, handlePost } = useAdd(table);
    return{ id, table, getTable, search, getTableBySearch, modalShow, form, handleAdd, handlePost }; }});Copy the code

Setup takes two arguments: props, context. You can return an object, each attribute of the object is proxy, listen to track, will be responsive rendering on the template.

Let’s focus on one of the logic, useTable, which normally starts with use

// VCADemo/composables/useTable.ts
// Logical function (1) correlation
import { ref, onMounted, watch, Ref } from 'vue';
import { ITable } from '.. /index.type';

const getTableApi = (id: number): Promise<ITable[]> => {
  const mockData: { [key: number]: ITable[] } = {
    1: [{id: '11'.name: "Zhang SAN 1 ' },
      { id: '12'.name: 'li si 1' },
      { id: '13'.name: 'fifty and 1'}].2: [{id: '21'.name: 'Joe 2' },
      { id: '22'.name: 'bill 2' },
      { id: '23'.name: 'fifty and 2'}};return new Promise(resolve= > {
    setTimeout(() = > {
      resolve(mockData[id] || []);
    }, 1000);
  });
};
export default function useTable() {
  const id = ref<number>(1);
  const table = ref<ITable[]>([]);
  const getTable = async () => {
    table.value = await getTableApi(id.value);
  };
  onMounted(getTable);
  watch(id, getTable);
  return {
    id,
    table,
    getTable
  };
}
Copy the code

We have isolated the related logic and “combined” it together, and you can see that in the Vue package there are many independent functions that we can use, which are no longer OO, and smell FP

This example first illustrates the benefits of VCA, the core of Vue3 is of course VCA, Vue3 is not only VCA, let us take a curious look ~

Life cycle, Vue2 vs Vue3

Optional API (Vue2) Hook Inside Setup (Vue3)
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered

Hook Inside Setup, as the name implies, VCA recommends writing our various logic function points inside the setup large method.

Teleport components

Transport, which mounts a component’s DOM element to any specified DOM element, is consistent with the concept of React Portals.

As a typical example, we call the Modal cartridge component in the component, and we want the cartridge to look like this, absolutely centered, highest level, as in:

The structure of the component looks like this

<Home>
  <Modal />
</Home>
Copy the code

But if the parent component Home has a style like this, such as transform:

It will affect the position of Modal, even if Modal uses position:fixed to locate, such as:

That’s why we need the Teleport component to help us “jump” out of the container and avoid the constraints of the parent component by mounting the component’s DOM element under the body, as in:

<Teleport to="body">
  <div v-if="show">. The DOM structure of the Modal component...</div>
</Teleport>
Copy the code

Note: Even when Modal is out of the container, the parent-child component relationship remains, but the DOM element is moved.

Asynchronous components (defineAsyncComponent)

Vue3 provides the defineAsyncComponent method and Suspense built-in components that you can use to make an elegant asynchronous component loading scheme.

Look directly at the code:

HOCLazy/index.tsx

import { defineAsyncComponent, defineComponent } from 'vue';
import MySuspense from './MySuspense.vue';
export default function HOCLazy(chunk: any, isComponent: boolean = false) {
  const wrappedComponent = defineAsyncComponent(chunk);
  return defineComponent({
    name: 'HOCLazy'.setup() {
      const props = { isComponent, wrappedComponent };
      return () = > <MySuspense {. props} / >; }}); }Copy the code

HOCLazy receives two arguments. Chunk is the asynchronous loading of components that we often use. Chunk =()=>import(xxx.vue), isComponent indicates that the current “component” is a component-level or page-level. By checking isComponent, different “loading” operations can be performed respectively.

HOCLazy/MySuspense.vue

<template>
  <Suspense>
    <template #default>
      <component :is="wrappedComponent"
                 v-bind="$attrs" />
    </template>
    <template #fallback>
      <div>
        <Teleport to="body"
                  :disabled="isComponent">
          <div v-if="delayShow"
               class="loading"
               :class="{component:isComponent}">
            <! There are two different ways to load components and pages.
            <div>{{isComponent? 'component level ':' page level '}}Loading...</div>
          </div>
        </Teleport>
      </div>
    </template>
  </Suspense>
</template>

<script lang="ts">
import { defineComponent, defineAsyncComponent, ref, onMounted } from 'vue';
export default defineComponent({
  name: 'HOCLazy'.props: ['isComponent'.'wrappedComponent'].setup(props) {
    const delayShow = ref<boolean>(false);
    onMounted(() = > {
      setTimeout(() = > {
        delayShow.value = true;
        // Delay is handled by itself, and can also be passed as props
      }, 300);
    });
    return{... props, delayShow }; }});</script>

<style lang="less" scoped>.loading {// component-level style &.component {} // page-level style}</style>
Copy the code

Explanation:

  1. Suspense components have two slots, named slotsfallbackLoading is a placeholder for the asynchronous component to be loaded before it is displayed.
  2. We also use Vue’s dynamic component to flexibly pass in an asynchronous component,v-bind="$attrs"To ensure that the props we passed to the target component did not disappear.
  3. In fallback, we use the judgment isComponent to show different loading, because we want the page-level loading to be “global” and the component-level loading to be in the original document flow, which is used hereTeleport :disabled="isComponent"To control whether to jump out.
  4. If you’re careful, you’ll notice that there’s a delaydelayShowIf we do not have this delay, in a good network environment, loading will flash by every time, and there will be a feeling of “anti-optimization”.

Call HOCLazy: To see the effect, we’ve wrapped the slow method to delay component loading:

utils/slow.ts

const slow = (comp: any, delay: number = 1000) :Promise<any> => {
  return new Promise(resolve= > {
    setTimeout(() = > resolve(comp), delay);
  });
};
export default slow;
Copy the code

Invocation (component level)

<template>
  <LazyComp1 str="hello~" />
</template>
const LazyComp1 = HOCLazy(
  () => slow(import('@/components/LazyComp1.vue'), 1000),
  true
);
// ...
components: {
  LazyComp1
},
// ...
Copy the code

Look at the effect:

React | user Experience | Hook version of lazy Loading

Ref, Reactive, toRef, toRefs

Ref (reference)

Ref and Reactive both exist to track value changes (reactive). Ref has a “wrapper” that wraps primitive value types such as String and number. We know that you cannot track subsequent changes without reference types. Ref returns an object containing the.value attribute.

setup(props, context) {
  const count = ref<number>(1);
  / / assignment
  count.value = 2;
  / / read
  console.log('count.value :>> ', count.value);
  return { count };
}
Copy the code

Ref Unwrapping objects are automatically wrapped in the template, so we don’t need.value in the template

<template>  
  {{count}}
</template>
Copy the code

reactive

This is the same concept as vue.Observable () in Vue2. Used to return a responsive object, such as:

const obj = reactive({
  count: 0
})
/ / change
obj.count++
Copy the code

Note: It is used to return a reactive object, which is itself an object, so it does not need to be wrapped. We use its properties, we don’t have to add.valueIn order to get.

toRefs

Because props are responsive, you can’t use ES6 deconstruction because it eliminates the responsiveness of prop.

Let’s focus on the props operations for the setup method:

<template>
  {{name}}
  <button @click="handleClick">Am I</button>
</template>
// ...
props: {
  name: { type: String, default: ' ' }
},
setup(props) {
  const { name } = props;
  const handleClick = () => {
    console.log('name :>> ', name);
  };
  return { handleClick };
}
// ...
Copy the code

Note: Props can also be bound to the corresponding value in template without having to return the setup function

We all know that deconstruction is a convenient way to compile into ES5, such as:

// es6 syntax
const { name } = props;
// to es5 syntax
var name = props.name;
Copy the code

If the parent component changes the props. Name value, when we click the button again, the output name will be the same as before.

To make it easier for us to package it, toRefs can be understood as a batch packaging props object, such as:

const { name } = toRefs(props); Const handleClick = () => {//.value console.log('name :>> ', name.value); };Copy the code

And that’s understandable because we’re going to use deconstruction,toRefsThe solutions adopted.

toRef

ToRef allows us to wrap a key with an extra argument, such as:

const name = toRef(props,'name');
console.log('name :>> ', name.value);
Copy the code

watchEffect vs watch

Vue3’s Watch method is similar to Vue2’s concept, and the watchEffect can be confusing. The watchEffect is similar to the Watch, except that:

Watch can do that

  • Lazy execution side effects
  • Be more specific about what state should trigger the listener to restart
  • Access values before and after listening state changes

As for the watch method of Vue2, the “watch” of Vue3 has a new concept of “removing side effects”, which we will focus on.

Here’s a watchEffect example:

WatchEffect: It executes a function passed in immediately, tracing its dependencies responsively, and rerunking the function when its dependencies change.

The watchEffect method has a simple structure

watchEffect(onInvalidate= > {
  // Perform side effects
  // do something...
  onInvalidate(() = > {
    // Execute/clean up the invalidation callback
    // do something...})})Copy the code

There are two opportunities for invalidation callbacks

  • When the side effect is about to be re-executed, that is, when the listening data is changed
  • Component uninstallation

An example: if we want to make a request for “fruit” details through an ID, we listen for the ID when it switches too frequently (before the asynchronous data returns successfully). We might end up with data with ID =1 overwriting data with id=2, which is not what we want.

Let’s simulate and solve this scenario:

The simulated interface getFruitsById

interface IFruit {
  id: number;
  name: string;
  imgs: string;
}
const list: { [key: number]: IFruit } = {
  1: { id: 1.name: 'apple'.imgs: 'https://xxx.apple.jpg' },
  2: { id: 2.name: 'banana'.imgs: 'https://xxx.banana.jpg'}};const getFruitsById = (
  id: number,
  delay: number = 3000) :Promise<IFruit>, () = > void] = > {let _reject: (reason? : any) = > void;
  const _promise: Promise<IFruit> = new Promise((resolve, reject) = > {
    _reject = reject;
    setTimeout(() = > {
      resolve(list[id]);
    }, delay);
  });
  return [
    _promise,
    () = >
      _reject({
        message: 'abort~'})]; };Copy the code

This encapsulates the “reject request” method, using reject to do so.

In the setup method

setup() {
  const id = ref<number>(1);
  const detail = ref<IFruit | {}>({});

  watchEffect(async onInvalidate => {
    onInvalidate(() = > {
      cancel && cancel();
    });
    // if id=2, request time is 1s, and id=1, request time is 2s
    const [p, cancel] = getFruitsById(id.value, id.value === 2 ? 1000 : 2000);
    const res = await p;
    detail.value = res;
  });
  // Change the id frequently, get the banana, get the apple result has not returned, cancel the apple request, ensure that the data will not be overwritten
  id.value = 2;
  / / the last detail value is {" id ": 2," name ":" banana ", "imgs" : "https://xxx.banana.jpg"}
}
Copy the code

If cancel() is not performed, the detail data will be {” ID “: 1, “name”: “apple “, “imgs”: “https://xxx.apple.jpg”} because id=1 is” late received “.

This is a common example in asynchronous scenarios of cleaning up failed callbacks to ensure that the current side effect is valid and not overwritten. Those of you who are interested can continue.

Fragment (fragment)

We all know that there can only be one root when encapsulating components. Vue3 allows us to have multiple roots, i.e. fragments, but some operations are worth noting.

When inheritAttrs=true[default], the component automatically inherits the class at root.

Child components

<template>
  <div class="fragment">
    <div>div1</div>
    <div>div2</div>
  </div>
</template>
Copy the code

Parent component call, adding a new class

<MyFragment class="extend-class" />
Copy the code

The child components will be rendered as

<div class="fragment extend-class">
  <div> div1 </div>
  <div> div2 </div>
</div>
Copy the code

If we use fragments, we need to explicitly specify the binding attrs, such as child components:

<template>
  <div v-bind="$attrs">div1</div>
  <div>div2</div>
</template>
Copy the code

emits

In Vue2 we want to validate the props by typing, default, non-null, etc. emits does something similar to this by normating the emit.

// You can also use arrays without validation
// emits: ['on-update', 'on-other'],
emits: {
  // Assigning null does not validate
  'on-other': null./ / verification
  'on-update'(val: number) {
    if (val === 1) {
      return true;
    }
    // Custom error reporting
    console.error('val must be 1');
    return false; }},setup(props, ctx) {
  const handleEmitUpdate = () = > {
    // Verify that val is not 1
    ctx.emit('on-update'.2);
  };
  const handleEmitOther = () = > {
    ctx.emit('on-other');
  };
  return { handleEmitUpdate, handleEmitOther };
}
Copy the code

In setup, emit is no longer used with this.$emit, but with the context context, the second argument to setup.

v-model

Personally, I like the update to the V-Model, which can improve the experience of packaged components

In Vue2, suppose I need to encapsulate an Modal popbox component and use the show variable to control how popboxes are shown and hidden, this must be a value maintained by both parent and child components. Because of one-way data flow, you need to emit an event in the Modal component, and the parent component listens for the event to receive and modify the show value. For convenience we will have some syntax sugar, such as V-model, but Vue2 can only have one V-Model on a component, because behind the syntax sugar is the composition of value and @input. If there are more “two-way modification data” like this, We need the syntactic sugar.sync sync modifier.

Vue3 unifies the two syntax sugars, so we can now use multiple V-Model syntax sugars on a component, for example:

Look at the parent component first

<VModel v-model="show"
        v-model:model1="check"
        v-model:model2.hello="textVal" />
Copy the code

Hello is a custom modifier

We used three V-Model syntactic sugars on one component, respectively

V – model syntactic sugar The corresponding prop The corresponding event Custom modifiers corresponding to prop
V – model (the default) modelValue update:modelValue There is no
v-model:model1 model1 update:model1 There is no
v-model:model2 model2 update:model2 model2Modifiers

This gives us a clearer idea of what we want to encapsulate in child components, such as:

VModel.vue

// ...
props: {
  modelValue: { type: Boolean.default: false },
  model1: { type: Boolean.default: false },
  model2: { type: String.default: ' ' },
  model2Modifiers: {
    type: Object.default: () = >({})}},emits: ['update:modelValue'.'update:model1'.'update:model2'].// ...
Copy the code

key attribute

<template>
  <input type="text"
         placeholder="Please enter your account number"
         v-if="show" />
  <input type="text"
         placeholder="Please enter email address"
         v-else />
  <button @click="show=! show">Toggle</button>
</template>
Copy the code

V-if/V-else like this, in Vue2, renders elements as efficiently as possible, usually reusing existing elements rather than rendering them from scratch, so when we type in the first input, then switch to the second input. The value of the first input will be retained for reuse.

There are scenarios where we don’t want to reuse them and need to add a unique key, such as:

<template>
  <input type="text"
         placeholder="Please enter your account number"
         v-if="show"
         key="account" />
  <input type="text"
         placeholder="Please enter email address"
         v-else
         key="email" />
  <button @click="show=! show">Toggle</button>
</template>
Copy the code

But Vue3 doesn’t explicitly add a key, and the two input elements are completely independent because Vue3 automatically generates a unique key for V-if/V-else.

Global API

In Vue2 we might do this for some global configurations, such as using a plug-in

Vue.use({
  / *... * /
});
const app1 = new Vue({ el: '#app-1' });
const app2 = new Vue({ el: '#app-2' });
Copy the code

But this will affect both root instances, that is, it will become uncontrollable.

Introduce a new API createApp method in Vue3 that returns an instance:

import { createApp } from 'vue';
const app = createApp({ / *... * / });
Copy the code

We can then mount globally relevant methods on this instance and apply only to the current instance, as in:

app
  .component(/ *... * /)
  .directive(/ *... * / )
  .mixin(/ *... * / )
  .use(/ *... * / )
  .mount('#app');
Copy the code

$Vue. Prototype =()=>{} $Vue. Prototype =()=>{} The enclosing $HTTP.

In Vue3 we mount something like this with a new globalProperties property:

app.config.globalProperties.$http = () = > {}
Copy the code

Use $HTTP inside setup:

setup() {
  const {
    appContext: {
      config: {
        globalProperties: { $http }
      }
    }
  } = getCurrentInstance()
}
Copy the code

2. Low-level optimization

The Proxy agent

The basic principle of Vue2 responsiveness is through Object.defineProperty, but this approach is flawed. Makes Vue have to hack by means such as:

  • Vue.$set() dynamically adds new responsive attributes
  • You can’t listen for array changes. Vue needs to encapsulate some of the array operations. Such aspush.pop Methods.

Vue3 preferentially uses Proxy to deal with it. It proxies the whole object rather than the attributes of the object and can operate on the whole object. Not only improved performance, but also no defects mentioned above.

Just two examples:

  1. Dynamically add reactive properties
const targetObj = { id: '1'.name: 'zhagnsan' };
const proxyObj = new Proxy(targetObj, {
  get: function (target, propKey, receiver) {
    console.log(` getting key:${propKey}`);
    return Reflect.get(... arguments); },set: function (target, propKey, value, receiver) {
    console.log(` setting key:${propKey}, the value:${value}`);
    return Reflect.set(...arguments);
  }
});
proxyObj.age = 18;
// Setting key: age, value: 18
Copy the code

As mentioned above, properties that we dynamically add to the proxyObj object using Proxy will also be intercepted.

The Reflect object is a new API provided by ES6 for manipulating objects. It has several built-in methods, such as get/set above, which we use to Reflect more conveniently, otherwise we would need to Reflect something like:

get: function (target, propKey, receiver) {
  console.log(`getting ${propKey}! `);
  return target[propKey];
},
Copy the code
  1. Intercepts operations on arrays
const targetArr = [1.2];
const proxyArr = new Proxy(targetArr, {
  set: function (target, propKey, value, receiver) {
    console.log(` setting key:${propKey}, the value:${value}`);
    return Reflect.set(...arguments);
  }
});
proxyArr.push('3');
// Setting key: 2, value: 3
// Setting key: length, value: 3
Copy the code

Static promotion (hoistStatic) vDOM

We all know that Vue has the concept of a virtual DOM, which allows us to render pages efficiently when data changes.

Vue3 optimizes vDOM update performance, as a simple example

Template

<div class="div">
  <div>content</div>
  <div>{{message}}</div>
</div>
Copy the code

After Compiler, there is no static improvement

function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", { class: "div" }, [
    _createVNode("div".null."content"),
    _createVNode("div".null, _toDisplayString(_ctx.message), 1 /* TEXT */)))}Copy the code

After Compiler, there is static improvement

const _hoisted_1 = { class: "div" }
const _hoisted_2 = /*#__PURE__*/_createVNode("div".null."content", -1 /* HOISTED */)

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

Static promotion includes the promotion of “static nodes” and “static attributes”, that is, we cache some static invariant nodes in variables to provide the next direct re-render call. If this action is not done, the tag will be recreated when render is re-executed, even if it is static, which incurs a performance cost.

3. With TS

A major design goal of 3.0 is to enhance TypeScript support. We had hoped to achieve this through the Class API, but after discussion and prototyping, we decided that Class was not the right approach to solve this problem, and that class-based apis still had typing problems. – especially the rain creek

Function-based apis naturally blend well with TS.

defineComponent

Under TS, we need to use the Vue exposed method defineComponent, which exists solely for type inference.

Props to deduce

import { defineComponent } from 'vue';
export default defineComponent({
  props: {
    val1: String.val2: { type: String.default: ' '}},setup(props, context){ props.val1; }})Copy the code

When we access props in the setup method, we can see the derived type,

  • Val1 we didn’t set the default, so it’sstring | undefined
  • Val2 has a value, so it has a valuestringAs shown in figure:

PropType

Let’s look at the type defined for props. If it’s a complex object, we’ll use PropType to enforce declarations, as in: props

interface IObj {
  id: number;
  name: string;
}

obj: {
  type: Object as PropType<IObj>,
  default: (a) :IObj= > ({ id: 1.name: 'Joe'})},Copy the code

Or union type

type: {
  type: String as PropType<'success' | 'error' | 'warning'>,
  default: 'warning'
},
Copy the code

4. Build by Better tree-sharking

Tree-sharking is the removal of useless code from the application after the build tool is built to reduce the size of the package.

The function-based API can use import {method1, method2} from “XXX” for each function; This is very tree-sharking friendly, and function names and variable names can be compressed, not objects. For example, we’ve wrapped a tool that provides two methods, method1, method2 instead.

We encapsulate them as an object and expose them, as in:

// utils
const obj = {
  method1() {},
  method2(){}};export default obj;
Copy the code
/ / call
import util from '@/utils';
util.method1();
Copy the code

After webpack packing and compression:

a={method1:function(){},method2:function(){}}; a.method1();Copy the code

Let’s look at this in terms of functions rather than objects:

// utils
export function method1() {}
export function method2() {}
Copy the code
/ / call
import { method1 } from '@/utils';
method1();
Copy the code

After webpack packing and compression:

function a(){}a();
Copy the code

Using this example we can see why Vue3 is better at tree-sharking because it uses a function-based API such as:

import {
  defineComponent,
  reactive,
  ref,
  watchEffect,
  watch,
  onMounted,
  toRefs,
  toRef
} from 'vue';
Copy the code

5. Options API vs. Composition API

The above code is implemented internally, but Vue3 still retains the options API of Vue2, which can “coexist”, for example:

// ...
setup() {
  const val = ref<string>(' ');
  const fn = () = > {};
  return {
    val,
    fn
  };
},
mounted() {
  // In the Mounted life cycle, objects from the Setup return can be accessed
  console.log(this.val);
  this.fn();
},
// ...
Copy the code

React, we know that “function”, hook is a trend of the future.

My personal recommendation is to write all the logic inside setup, because Vue3 provides all the capabilities of Vue2.

conclusion

In my opinion, whether React Hook or Vue3’S VCA, we can see the trend of the current front-end framework, which is “more functional”, making logic reuse more flexible. Hook mode added the React/Vue abstraction level, “component-level + function-level”, which allows us to process logic in finer detail and easier maintenance.

Vue3 One Piece, nice!

Finally, I wish you a merry Christmas 🎄~ (I heard that the public number concerned about “front-end sperm” will be more happy oh ~