编程知识 cdmana.com

Vue3: from five dimensions, vue3 changes

Some of the concepts

Vue Composition API(VCA) In reality, it's just a matter of putting Vue The responsive system itself is more explicitly exposed .

It's not a function , It's just API Exposed as a function .

3.0 Template Compiled performance will be better than handwriting jsx Several times faster .

—— Especially the rain creek

Vue2 Conventional data,computed,watch,methods How to write it , We call it 「 Optional api(Options API )」
Vue3 Use Composition API (VCA) Code can be organized according to logical functions , A function related api It will be put together .

Vue and React Logical reuse means of

up to now ,

Vue:Mixins( Mix in )、HOC( High order component )、 Scope slot 、Vue Composition API(VCA/ combined API).

React:Mixins、HOC、Render Props、Hook.

We can see that it is a growing history , I won't give an example here , This paper focuses on VCA,VCA More inclined 「 Combine 」 The concept of .

5 In terms of two dimensions Vue3

1. frame

Let's start with an example VCA

stay Vue in , With the concept of abstract encapsulation components , The more modules are solved on the page , More and more bloated . But even with component encapsulation , As the application gets bigger and bigger , You will find that there are more and more logical function points on the page , data/computed/watch/methods Will be constantly crammed into logical functions , So we need to separate and combine the logic again 、 Reuse , This is it. VCA.

A simple example :

We want to achieve 3 A logic

  1. according to id Get the table data
  2. The table data can be searched and filtered
  3. Pop up to add data to the table
Vue2 options api To deal with

For reading quality , Some code is omitted , But it doesn't affect our understanding of 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: ' Wang Wu 1' }
    ],
    2: [
      { id: 21, name: ' Zhang San 2' },
      { id: 22, name: ' Li Si 2' },
      { id: 23, name: ' Wang Wu 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;
    }
  }
};

Here's just a simple example of logic . If the project is complicated , Logic has increased . It involves a logical change , We may need to modify the same function points distributed in different locations , Increased maintenance costs .

Vue3 composion api To deal with

Let's focus on logic , Take away logic , Let's look at the code structure of the main 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
    };
  }
});

setup Receive two parameters :props,context. You can return an object , Each attribute of an object is proxy Of , Monitoring and tracking , Reactive rendering will be done on the template .

Let's focus on one of the logic ,useTable, Generally speaking, we use use Name it at the beginning , It has that flavor ~

// VCADemo/composables/useTable.ts
//  logic function (1) relevant 
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: ' Wang Wu 1' }
    ],
    2: [
      { id: '21', name: ' Zhang San 2' },
      { id: '22', name: ' Li Si 2' },
      { id: '23', name: ' Wang Wu 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
  };
}

We separate the relevant logic , and 「 Combine 」 Together , You can see in the vue The package exposes many independent functions for us to use , No more OO 了 , Smell a wave of FP The breath of ~

The above example illustrates VCA The benefits of ,Vue3 The core of this is, of course VCA,Vue3 not only VCA, Let's look down with curiosity ~

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, seeing the name of a thing one thinks of its function ,VCA It is suggested that setup In this big method, we write all kinds of logic function points .

Teleport Components

delivery , Will be the component of DOM The element is mounted on any specified DOM Elements , And React Portals The concept of is consistent .

A typical example , We call in the component Modal Frame assembly , This is what we want the box to look like , Absolutely in the middle , Highest level , Such as :

The structure of the component looks like this

<Home>
  <Modal />
</Home>

But if in the parent component Home There are styles like this , Such as transform

Will affect Modal The location of , Even if Modal It was used position:fixed To locate , Such as :

That's why we need to use Teleport Components to help us “ Jump out of ” Containers , Avoid being controlled by some constraints of the parent component , Put the components DOM The elements are attached to body Next , Such as :

<Teleport to="body">
  <div v-if="show">
    ...Modal  Component's  DOM  structure ...
  </div>
</Teleport>

Be careful : Even if Modal Out of the container , And keep it “ Parent child relationship ”, It's just DOM The position of the element has been moved .

Asynchronous component (defineAsyncComponent)

We all know that Vue2 There is also the concept of asynchronous components , But on the whole, it's not complete ~,Vue3 Provides defineAsyncComponent Methods and Suspense Built in components , We can use them 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} />;
    }
  });
}

explain :HOCLazy Two parameters are received ,chunk It's a common way to load components asynchronously, such as :chunk=()=>import(xxx.vue),isComponent Represents the current “ Components ” It's a Component level or Page level , By judgment isComponent To correspond to different “loading” operation .

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 kinds of components and pages loading The way , I don't want to encapsulate it in detail here  -->
            <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  Do it yourself , You can also use  props  By 
      }, 300);
    });
    return { ...props, delayShow };
  }
});
</script>

<style lang="less" scoped>
.loading {
  //  Component level styles 
  &.component {
  }
  //  Page level styles 
}
</style>

explain :

  1. Suspense The component has two slots , A named slot fallback We can understand it as a loading Placeholder for , Before the asynchronous component displays the backup content before .
  2. It's also used here Vue Dynamic components of component To flexibly pass in an asynchronous component ,v-bind="$attrs" To ensure that we pass to the target component props It won't go away .
  3. fallback We make use of judgment isComponent To show different loading , Because we want page level loading yes “ overall situation ” Of , Component level is in the original document flow , This is used here. Teleport :disabled="isComponent" To control whether to jump out of .
  4. Careful little friends will find that there is a delay display delayShow, If we don't have this delay , In a good network environment ,loading Every time it flashes by , There will be a kind of “ Anti optimization ” The feeling of .

call HOCLazy:
In order to see the effect better , We encapsulate 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;

call ( Component level )

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

Look at the effect :

In fact, this is related to React Medium React.lazy + React.Suspense The concept of is consistent , An article I wrote before 《React User experience hook edition lazy loading》, You can have a look and make a comparison ~

ref,reactive,toRef,toRefs The difference between the use of

ref(reference)

ref and reactive It's all about tracking value changes ( Response type ),ref There is one 「 packing 」 The concept of , It's used to wrap primitive value types , Such as string and number , We all know that you can't track subsequent changes without reference types .ref The returned one contains .value Object of property .

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

stay template in ref The wrapper object is automatically expanded (Ref Unwrapping), That is, we don't need to .value

<template>  
  {{count}}
</template>
reactive

And Vue2 Medium Vue.observable() It's a concept .
Used to return a responsive object , Such as :

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

Be careful : It is used to return a responsive object , Itself is the object , So there's no need for packaging . We use its properties , No need to add .value To get .

toRefs
Official website : because props It's reactive , You can't use ES6 deconstruction , Because it will eliminate prop Responsiveness .

Let's focus on setup Methodical props Related operations of :

<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 };
}
// ...

Be careful :props There is no need to pass setup function return, It can also be in template Bind the corresponding value

We all know that deconstruction is es6 A convenient means , Translate it into es5 , Such as :

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

Suppose the parent component changes props.name value , When we click again button Output name It's the same as before , It doesn't change , This is actually a basic js Knowledge points of .

In order to make it convenient for us to pack it ,toRefs It can be understood as batch packaging props object , Such as :

const { name } = toRefs(props);
const handleClick = () => {
  //  Because it's the packaging object , So when reading, use .value
  console.log('name :>> ', name.value);
};

It's understandable that all of this is because we're going to use deconstruction ,toRefs The solution taken .

toRef

toRef Usage of , It's just one more parameter , Allow us to target at a key For packaging , Such as :

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

watchEffect vs watch

Vue3 Of watch Methods and Vue2 The concept of is similar to ,watchEffect It's going to make us wonder . Actually watchEffect And watch Broadly similar , The difference lies in :

watch doable

  • Lazy executive side effects
  • More specifically, what state should trigger the listener to rerun
  • Access the values before and after the listening state changes

about Vue2 Of watch Method ,Vue3 Of "watch" One more. 「 Remove side effects 」 The concept of , We focus on this .

Here watchEffect For example :

watchEffect: It immediately executes an incoming function , At the same time, it is responsive to trace its dependencies , And rerun the function when its dependency changes .

watchEffect Method simple structure

watchEffect(onInvalidate => {
  //  Executive side effects 
  // do something...
  onInvalidate(() => {
    //  perform / Clean up invalid callbacks 
    // do something...
  })
})

Perform the invalidation callback , There are two opportunities

  • When the side effects are about to be repeated , That is, when the monitored data changes
  • When the component is uninstalled

An example : We're going to pass id Initiate a request to get 「 Fruits 」 Details of , We monitor id, When id Switching too often ( Before the last asynchronous data is returned successfully ). It could lead to id=1 The data covered by id=2 The data of , This is not what we want .

Let's simulate and solve this scenario :

Analog 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~'
      })
  ];
};

It encapsulates “ Cancel the request ” Methods , utilize reject To do this .

stay setup Method

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

  watchEffect(async onInvalidate => {
    onInvalidate(() => {
      cancel && cancel();
    });
    //  simulation id=2 Ask for the time when you're going to  1s,id=1 Ask for the time when you're going to  2s
    const [p, cancel] = getFruitsById(id.value, id.value === 2 ? 1000 : 2000);
    const res = await p;
    detail.value = res;
  });
  //  Simulate frequent switching id, When you get bananas , The results of getting apple have not come back yet , Cancel Apple's request , Make sure the data is not covered 
  id.value = 2;
  //  Last  detail  The value is  { "id": 2, "name": " Banana ", "imgs": "https://xxx.banana.jpg" }
}

If not implemented cancel() , that detail The data will be { "id": 1, "name": " Apple ", "imgs": "https://xxx.apple.jpg" }, because id=1 Data comparison “ I got it late ”.

This is a common example in asynchronous scenarios , Clean up invalid callbacks , Ensure that the current side effects are effective , Will not be covered . If you are interested, you can continue to study .

fragment( fragment )

We all know that when we encapsulate components , There can only be one root . stay Vue3 Allow us to have multiple root , That's the clip , But in some operations, we should pay attention to .

When inheritAttrs=true[ Default ] when , The component will automatically be in root Inheritance and merger class , Such as :

Child components

<template>
  <div class="fragment">
    <div>div1</div>
    <div>div2</div>
  </div>
</template>

Parent component call , I added a new one class

<MyFragment class="extend-class" />

The subcomponents are rendered as

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

If we use fragment , You need to explicitly specify the binding attrs , Such as subcomponents :

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

emits

stay Vue2 We will be right. props The data in the specified type , The default value is , Non empty wait for some verification , You can understand emits Did something similar , hold emit Standardize , Such as :

//  You can also use arrays directly , No verification 
// emits: ['on-update', 'on-other'],
emits: {
  //  assignment  null  Don't verify 
  '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 = () => {
    //  verification  val  Not for  1, Console error 
    ctx.emit('on-update', 2);
  };
  const handleEmitOther = () => {
    ctx.emit('on-other');
  };
  return { handleEmitUpdate, handleEmitOther };
}

stay setup in ,emit No more this.$emit 了 , It is setup Second parameter of context Context to get emit .

v-model

I still like v-model Updated by , It can enhance the experience of packaged components ~

stay Vue2, Suppose I need to encapsulate a spring box component Modal, use show Variable to control the display and hide of the pop-up box , This must be a value to be maintained by both parent and child components . Because of one-way data flow , So you need to be in Modal Components emit An event , The parent component listens for events, receives and modifies this show value .
For convenience, we will have some grammar sugar , Such as v-model, But in Vue2 There can only be one on a component v-model , Because behind the grammar sugar is value and @input The composition of , If there are more than one like this “ Two way modification of data ”, We need sugar .sync Sync modifier .

Vue3 Unify these two grammatical sugars , So we can now use it on a component Multiple v-model Grammatical sugar , for instance :

Let's start with the parent component

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

hello For custom modifiers

We used... On a component 3 individual v-model Grammatical sugar , Namely

| v-model Grammatical sugar | Corresponding prop | Corresponding event | Custom modifiers correspond to prop |
| -------- | ----- | ----- | ----- |
|v-model(default)| modelValue | update:modelValue | nothing |
| v-model:model1 | model1 | update:model1 | nothing |
|v-model:model2 | model2 | update:model2 | model2Modifiers |

In this way, we can make it clearer what kind of encapsulation we are going to make in the sub 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'],
// ...

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>

Something like that v-if/v-else, stay Vue2 in , Render elements as efficiently as possible , Often reuse existing elements rather than rendering from scratch , So when we're in the first input Input in , Then switch to the second
input . first input The value of will be reserved for reuse .

In some scenarios, we don't reuse them , The only need to add 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>

But in Vue3 We don't have to explicitly add key , these two items. input The elements are also completely independent , because Vue3 Would be right v-if/v-else Automatically generate unique key.

overall situation API

stay Vue2 Our global configuration may look like this , For example, we used a plug-in

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

But this affects two root instances , in other words , It's going to get out of control .

stay Vue3 Introduce a new API createApp Method , Return an instance :

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

Then we can mount the global correlation method on this instance , And only for the current instance , Such as :

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

It should be noted that , stay Vue2 We use the Vue.prototype.$http=()=>{} This way of writing , Come on “ root Vue” Of prototype How to mount , Make us in the sub component , It can be found by the way of prototype chain $http Method , namely this.$http.

And in the Vue3 We need a new attribute for mounting like this globalProperties

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

stay setup For internal use $http

setup() {
  const {
    ctx: { $http }
  } = getCurrentInstance();
}

2. Bottom level optimization

Proxy agent

Vue2 The basic principle of response , It is through Object.defineProperty, But there are flaws in this approach . bring Vue It has to be done by some means hack, Such as :

  • Vue.$set() Dynamically add new responsive properties
  • Unable to listen for array changes ,Vue The bottom layer needs some operation methods for arrays , Repackaging . Such as push,pop Other methods .

And in the Vue3 In the first place Proxy To deal with it , It represents the entire object, not its properties , You can manipulate the entire object . Not only does it improve performance , There are no defects mentioned above .

Two simple examples :

  1. Dynamically add responsive 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},value:${value}`);
    return Reflect.set(...arguments);
  }
});
proxyObj.age = 18;
// setting key:age,value:18

Above , use Proxy We are right. proxyObj Properties added dynamically by objects will also be intercepted .

Reflect The object is ES6 New... For manipulating objects API. It has several built-in methods , Just like the one above get / set, We use Reflect It is more convenient , Otherwise we need to be like :

get: function (target, propKey, receiver) {
  console.log(`getting ${propKey}!`);
  return target[propKey];
},
  1. Intercept the operation of array
const targetArr = [1, 2];
const proxyArr = new Proxy(targetArr, {
  set: function (target, propKey, value, receiver) {
    console.log(`setting key:${propKey},value:${value}`);
    return Reflect.set(...arguments);
  }
});
proxyArr.push('3');
// setting key:2,value:3
// setting key:length,value:3

Static lift (hoistStatic) vdom

We all know Vue Virtual dom The concept of , It can render pages efficiently when data changes .

Vue3 To optimize the vdom Update performance of , Just a quick example

Template

<div class="div">
  <div>content</div>
  <div>{{message}}</div>
</div>

Compiler after , There is no static Promotion

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 */)
  ]))
}

Compiler after , There are static improvements

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 */)
  ]))
}

Static promotion includes 「 Static nodes 」 and 「 Static attribute 」 The promotion of , in other words , We cache some static and unchanging nodes with variables , Offer next time re-render Call directly .
If you don't do it , When render When reexecuting , Even if the tag is static , It will also be recreated , This leads to performance consumption .

3. And TS

3.0 One of the main design goals of is to enhance the TypeScript Support for . Originally we expected to pass Class API To achieve this goal , But after discussion and prototyping , We think Class It's not the right way to solve this problem , be based on Class Of API There are still types of problems .—— Especially the rain creek

Function based API natural And TS Perfect combination .

defineComponent

stay TS Next , We need to use Vue Methods of exposure defineComponent, It exists purely for the purpose of type deduction .

props deduction

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

When we're in setup Method access props When , We can see the derived type ,

  • val1 We didn't set the default , So it's for string | undefined
  • and val2 The value of has a value , So it is string, Pictured :

PropType

Let's focus on props The type of definition , If it's a complex object , We're going to use it PropType To make a forced transfer statement , Such as :

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

obj: {
  type: Object as PropType<IObj>,
  default: (): IObj => ({ id: 1, name: ' Zhang San ' })
},

or Joint type

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

4. build Better tree-sharking( Shaking tree optimization )

tree-sharking That is to eliminate useless code in the program after the build tool is built , To reduce the size of the package .

Function based API Every function can use import { method1,method2 } from "xxx";, That's right tree-sharking Very friendly , And function names and variable names can be compressed , The object can't go . for instance , We encapsulate a tool , Tools provide two ways , use method1,method2 Instead of .

We encapsulate them into an object , And exposed , Such as :

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

after webpack After packing and compressing, it is :

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

We don't use the form of objects , And in the form of a function :

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

after webpack After packing and compressing, it is :

function a(){}a();

With this example, we can understand Vue3 Why better tree-sharking , Because it's based on function form API, Such as :

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

5. options api And composition api trade-offs

The code above is all in setup Internal implementation , But at the moment Vue3 And kept Vue2 Of options api How to write it , It can be “ Coexist ”, Such as :

// ...
setup() {
  const val = ref<string>('');
  const fn = () => {};
  return {
    val,
    fn
  };
},
mounted() {
  //  stay  mounted  The lifecycle has access to  setup return  Out object 
  console.log(this.val);
  this.fn();
},
// ...

combination react , We know “ Functional expression ”,hook It's a trend in the future .

So it's all about personal suggestions or adoption setup The way logic is written internally , because Vue3 It's completely available Vue2 All capabilities of .

summary

I feel that no matter it is React Hook still Vue3 Of VCA, We can all see the trend of front-end framework now ,“ More functional ”, Make logic reuse more flexible .hook The new mode of React / Vue The level of abstraction ,「 Component level + Function level 」, It allows us to deal with logic in more detail , Better maintenance .

Vue3 One Piece,nice !

Last , Happy Christmas to you ~ ( I heard that the official account is concerned 「 Front end fine 」 Will be happier ~

版权声明
本文为[Front end fine]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201225104724938f.html

Scroll to Top