preface

Vue3.0 was officially released in September last year, with some new apis and the arrival of dark magic, some developers are already using it in newly created projects, some are upgrading, and some are still waiting. So today we don’t talk about internal power (source), only talk about vue3.0 routines, how to develop a school of their own in the Martial arts.

One, ten thousand swords return to the family

Wanjian return is the highest realm of jianshu, once the use of wanjian return as a servant to see the Lord, such as worship to the general god. Sword recruit a, sharp without the sword strength born from the body, the body can be a smoke, the strength of the gas scattered in the air. A thousand swords flew in a storm. Flying all over the sky, the sword is as powerful as a net. Can also manipulate the sword to launch attacks.

The return of ten thousand swords in swordsmanship indicates the highest realm of swordsmanship, while the H function in VUe3.0 can cover the rendering of all DOM trees and binding of events and attributes.

2.1H Rendering function introduction

Vue recommends using templates to create your HTML in most cases. However, in some scenarios, you really need the full programming power of JavaScript. In this case you can use render functions, which are closer to the compiler than templates.

2.1.1 Slot Rendering

There is a component called Demo, which has a slot name demoSlot inside it. The h rendering function is written as:

2.1.2 Event Binding

We must provide an appropriate prop name for the event handler, for example, to handle the click event, the prop name should be onClick.

2.2 Writing examples

import { defineComponent, h } from 'vue'; export default defineComponent({ name: 'renderDemo', props: ['modelValue'], setup(props, { slots, emit }) { return () => { return h('demo', { // dom style style: {}, // class style name class: [], // dom custom attribute 'data-id': '123456', // v-on, @ directive example onClick: event => { console.log('event', event); }, // demoSlot demoSlot: () => {return h('div', '1111'); }, // v-model example modelValue: props. ModelValue, 'onUpdate:modelValue': value => emit('update:modelValue', value)})}; }});Copy the code

More: github.com/vuejs/rfcs/…

Two, layer upon layer fall wave palm

Layer wave stack wave, cloud shu wave volume, interlocking, continuous.

1.1 Recursive component rendering

const vnodeSchema = {
  id: '001',
  class: 'parent-class',
  componentName: 'demo',
  children: [
    {
      id: '00101',
      class: 'children-class',
      componentName: 'demo',
    },
    {
      id: '00101',
      class: 'children-class',
      componentName: 'demo',
    }
  ]
}
Copy the code

Idea is: According to the componentName name, obtain the component instance vNode using resolveComponent, parse the component properties in vnodeSchema, return the real props, and finally call the H rendering function. Render the Vnode node and perform props assignment. Recursive calls render DOM nodes dynamically as described by vnodeSchema.

Three, Yin and Yang bipolar sword

It was created by huangmu Daoist, and the two of them work together to attack and defend each other. According to the hexagrams of The Book of Changes, the sword recruits people to be born and to be destroyed.

The purpose of the sword is one attack, one defense, and endless growth. In VUe3.0, responsive data focuses on reading and writing, respectively triggering get and set collected in dependency.

3.1 Introduction to responsive data API

3.1.1 reactive

Receive a common object and return the Proxy for that common object. By default, deep-level proxies are used. If deep-level proxies are not needed in a project, shallowReactive can be used to improve performance.

In Vue.js 3.0, the reactivity module encapsulates a set of tools for reactive systems, which can be used for boundary determination and type conversion in internal source code. Exporting these methods allows users to use their own scenarios. MarkRaw and shallowXXX are used to skip the depth proxy. For example, when rendering a large number of elements, but the data is immutable, skipping Proxy transformations can provide performance gains.

let result = { description: { version: '2.0'}};const resultProxy = reactive(result); 
console.log(isReactive(resultProxy.description)); // true
Copy the code

3.1.2 ref

Accepts a parameter value and returns a reactive and mutable REF object. The REF object has a single property that points to an internal value, and if a REF is passed in to an object, the reactive methods are called for a deep response transformation.

3.1.3 toRef

You can use it to create a REF for a property on a source reactive object. You can then pass the REF out, preserving a reactive connection to its source property.

3.1.4 toRefs

Converts a reactive object to a normal object, where each property of the resulting object is a REF pointing to the corresponding property of the original object.

Solve the problem of lost response feature of deconstructed assignment: lost data response, you will find that the data has changed, the view has not changed.

// combine functions:
function useMousePosition() {
  const pos = reactive({
    x: 0.y: 0,})return pos;
}

// Consumer components
export default {
  setup() {
    // Destruct assignment loses responsiveness!
    const { x, y } = useMousePosition()
    return {
      x,
      y,
    }

    // This also loses responsiveness!
    return {
      ...useMousePosition(),
    }

    // Keep it responsive!
    // You must return 'pos' itself and reference x and y in the template in the manner of' pos. X 'and' pos. Y '.
    return {
      pos: useMousePosition(),
    }
  },
}

// Or in combinatorial functions
function useMousePositionRef() {
  const pos = reactive({
    x: 0.y: 0,})/ / use toRefs
  return{... toRefs(pos)}; }Copy the code

3.2 Vue3.0 relies on collection implementation

Vue. Js 2.0 first invokes all the data used to trigger all the getters, then collects all the reactive dependencies through the Dep object, and invokes all the Watcher to perform the Render operation, which stores and compares the virtual Dom to Render the page. Setter functions are triggered when there is a data change, triggering dep.notify(), which calls Watcher’s update, pushes into Vue’s asynchronous watch queue, and eventually renders to the page.

A vue.js 2.0 dependent collection brain map is drawn here

Vue.js 3.0 transforms data into proxies through the Reactive module, and then proxies through Proxy. Handle intercepts all kinds of GET and SET operations. When GET operations are performed, track method in effect module will be called for dependent collection. Trigger is triggered by an effect trigger.

A vue.js 3.0 dependent collection brain map is drawn here

3.2.1 Object.defineProperty Comparison with Proxy

Object.defineProperty
  • Only properties of objects can be hijacked;
  • Modify the original value;
Proxy
  • Proxy objects, no recursive traversal of properties, performance improvements, use Reflect to solve deep nesting;
  • Proxy, relative to the defineProperty undoubtedly even more powerful, can be agents arrays, objects, methods, and provides the intercept property access method is operated in the 13 traps (get, set, has, deleteProperty, etc.);
  • Proxying raw data does not change the value of the raw data;

3.3 Data Sharing across Components

Often in our projects we have some deeply nested components, and the deep child component only needs part of the parent component. In this case, it can be cumbersome to still pass prop down the chain of components. In this case, we can use vuex or a pair of provide and Inject for cross-component data sharing.

No matter how deep the component hierarchy is, a parent component can act as a dependent provider for all its children. This feature has two parts: the parent component has a provide option to provide data, and the child component has an Inject option to start using that data.

4.3.1 Project application

We use provide in the outermost root component, and all descendant components inside it can receive data using Inject. If their data is changed, watch, watchEffect, computed will be re-executed where this variable is used, and the relevant DOM that the variable depends on will be re-rendered. Data changes are made across components, and views are updated.

globalProvide.tsx

import { defineComponent, provide, reactive, Fragment } from 'vue'; export default defineComponent({ name: 'globalProvide', setup(props, {slots}) {// Support (props, {slots}) {// Support (props, {slots}) {// Support (props, {slots}) { currentPage: 0, }, }); provide('globalData', globalData); return () => { return <Fragment>{slots.default?.()}</Fragment>; }; }});Copy the code

center.vue

The outermost component uses the component encapsulated above, and the global data defined by Provide is available to all the deeper components inside.

<template>
  <globalProvide>
    <leftComponent/>
    <rightComponent/>
  </globalProvide>
</template>
Copy the code

leftComponent.tsx

Components of globalData data changed, all other deep components, of globalData. CTX. CurrentPage dependence, automatically update related, and the view.

import { defineComponent, inject, onMounted } from 'vue';

export default defineComponent({
  name: 'leftComponent',
  setup() {
    const globalData = inject('globalData');
    onMounted(() => {
      globalData.ctx.currentPage = 2;
    })
    return () => {
      return (
        <div>{globalData.ctx.currentPage}</div>
      )
    }
  }
})
Copy the code

We can see that the ConfigProvider global configuration in Ant-design-vue is also implemented this way.

The roar of the lion

The supreme internal strength of Shaolin school is the deep internal force contained in a sound, which has the effect of deterring enemies, police and friends.

In Martial arts, the lion roar can be used to make the opponent feel the transmission of sound, but in VUe3.0, how to achieve cross-component communication between components? Look at our example below.

5.1 emits is introduced

emits can be arrays or objects that trigger custom events from components, and emits can be simple arrays or objects that allow event validation to be configured.

5.1.1 emits validation

Examples of child components:

import { defineComponent } from 'vue';
export default defineComponent({
  name: 'demoEmits'.// The emits message can be verified
  emits: {
    clickItem: ({type}) = > {
      // type == ok
      if (type= ='ok') {
        return true;
      }
      // Otherwise prompt
      console.warn('Verification failed'); }},setup(props, {slots, emit}) {
    const clickHandle = (event) = > {
      emit('clickItem', {type: 'ok'});
    }
    const demoProps = {
      style: {},
      class: [].onClick: clickHandle,
    }
    return () = > {
      <div {. demoProps} >Send a message</div>}}})Copy the code

5.2 Father-son Communication:

When vue2.0 is used, parent-child communication is commonly used. This section does not elaborate on this topic. You can refer to the example above for subcomponents.

Example parent component:

<demo-emits @clickItem="() => console.log('demoFn')"/>
Copy the code

5.2.2 Cross-component communication

Communication across components is particularly important in real-world development scenarios where deep-level components communicate with other components. Vue3.0 does not support the VUe2.0 Event-bus mode for cross-component message communication. A tripartite library is officially provided to recommend mitt or Tiny-Emitter, and mitt is used in this example.

Mount the methods of the tripartite library in the eventBus namespace in the globally shared data defined by provide.

This deeply nested component can send messages via the Globaldata.eventbus. on method, which is the same as eventBus.

import { defineComponent, provide, reactive, Fragment } from 'vue'; import mitt from 'mitt'; export default defineComponent({ name: 'globalProvide', setup(props, { slots }) { const emitter = mitt(); Const globalData = reactive({CTX: {currentPage: 0,}, eventBus: Emitter,}); provide('globalData', globalData); return () => { return <Fragment>{slots.default?.()}</Fragment>; }; }});Copy the code

For other alternatives, see Event-bus.

Sixth, key summary

  1. hRender functions can be used flexibly, and styles, styles, custom attributes, instructions, event binding, slot rendering, can also be usedJSXSyntax makes code more readable.
  2. vue2.0vue3.0Data proxy implementation scheme differences.
  3. You can useprovideRealize data sharing of deep components and message communication mechanism across components (tripartite library MITT).

Processon invite link

References:

  1. Vue3js. Cn/docs/API/op…
  2. V3.cn.vuejs.org/guide/migra…
  3. 2 x.antdv.com/components/…
  4. Github.com/vuejs/jsx-n…
  5. Github.com/vuejs/rfcs/…