Vue2 development projects, want to directly use vue3 quickly, a few API familiar enough, other features in the process of using Vue3 slowly to understand. Anyone who studies the principles of the API after they are familiar with it will gradually master VUE3.

In addition, with the use of VUe3 and TS, the proportion of TS in the development process is not so big. The basic knowledge of TS shared before is enough for development.

Global API and application API

A new concept of VUe3 that returns an application instance that provides an application context shared by the entire component tree mounted by the application instance:

const app = createApp(App);
app.use(store).use(router).mount("#app");
Copy the code

Vue2:

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");
Copy the code

Then the API that used to use Vue. Is changed to use the instance app. :

vue2 vue3
Vue.component app.component
app.config app.config
app.directive app.directive
app.mixin app.mixin
app.use app.use

Other apis like nextTick and H are used directly from the Vue structure:

import { createApp, h, nextTick } from 'vue'
Copy the code

composition API

tips

  • Vue3 no longer uses this
  • The VUE3 component does not require a root tag, but has a warning Extraneous non-props Attributes
  • Single-file components are recommended. The following implementation code is single-file components

setup

This is so important that VUe3 uses this function as an entry point. Accepts two parameters, props and context. The function is executed before beforeCreate and Created, so it can replace beforeCreate and Created as the new life cycle. The new composition API is written in the setup function.

Props is props of vue2. Context provides attrs, slots, emit, and so on. To return an object, we expose the response data to the template, equivalent to vue2’s data, except that the function is also exposed to template in the same way:

<template> <div class="hello"> <h1>{{ msg }}</h1> <h1 @click="test">{{ isRef }}</h1> </div> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; export default defineComponent({ name: "HelloWorld", props: { msg: String, }, setup(props) { console.log(props.msg); let isRef = ref("is ref"); const test = () => { console.log(isRef.value); }; return { isRef, test, }; }}); </script>Copy the code

Single file component

Vue3 also provides a single-file component (recommended) where setup is added to a script and the code inside is compiled into a Setup function. A few more important points:

The top-level binding is exposed to the template

The top-level bindings of declarations (including variables, function declarations, and import imports) can be used directly in templates with reactive data, components, etc.

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h1 @click="test">{{ isRef }}</h1>
  </div>
<MyComponent />
</template>

<script lang="ts" setup>
import MyComponent from './MyComponent.vue'
import { ref } from "vue";
const msg = "msg";
const isRef = ref("");
function test() {
  console.log(isRef.value);
}
</script>
Copy the code

With single-file components, the use of some attributes also changes, and there are alternative apis as well:

attribute The corresponding
Props and emits DefineProps and defineEmits
Ref or $parent defineExpose
Slots and attrs UseSlots and useAttrs ()

ref

It takes an internal value and returns a responsive, mutable ref object. To access the ref function inside the setup function, add. Value. If you want to add a type, use a generic type.

const ref1 = ref(1); const ref2 = ref<number>(2); const ref3 = ref1.value; Const ref4 = ref(); // use undefined constant refs.value = 5; // Assignment reads with.valueCopy the code

If an object is assigned to a REF value, it will be processed by Reactive as a deep reactive object:

Const ref1 = ref({a: 10,}); / / not sure type const ref3 = ref < string | number > (); ref3.value = 1; ref3.value = ""; // Array object, ts type declaration, using the generic type Obj1 = {c: string}; type Obj2 = { b: string; c: Obj1[]; }; const ref2 = ref<Obj2[]>([ { b: "", c: [{ c: "" }], }, ]);Copy the code

reactive

Used to declare reactive objects whose types are added by generics:

type Obj = {
  a: number;
  b: string;
};
let obj = reactive<Obj>({
  a: 10,
  b: "",
});
let state = reactive({
  a: 10,
  b: "",
});
Copy the code

Reactive will unpack all deep refs while maintaining the responsiveness of refs. Refs are automatically unpacked when assigned to reactive properties. The value of ref and the value of Reactive

Const count = ref(1) const obj = reactive({count}) console.log(obj.count === count.value) // true // it updates 'obj.count' count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // It also updates' count 'ref obj.count++ Console. log(obj.count) // 3 console.log(count.value) // 3 console.log(count.value) // 3 obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // trueCopy the code

toRef

Create a ref (reactive) for a property on the source reactive object to maintain a reactive connection to its source property:

const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) // 2

state.foo++
console.log(fooRef.value) // 3
Copy the code

toRefs

Convert a reactive object to an ordinary object, where each property of the resulting object is a ref to the corresponding property of the original object:

Const state = reactive({foo: 1, bar: 2}) const stateAsRefs = toRefs(state) Ref<number>, bar: Ref<number>} */ // the original property is linked state.foo++ console.log(stateasrefs.foo.value) // 2 stateAsRefs.foo.value++ console.log(state.foo) // 3Copy the code

ToRefs and toRefs can be useful for expanding reactive object structures, so look at them when they are useful.

watch

Watch receives two parameters. The first parameter can be a function with return or a ref. The second parameter is the same function as vue2.

// let count = ref(0); watch( () => count.value, (val, old) => { console.log(old, val); }); // single ref recommends watch(count, (val, old) => {console.log(old, val); }); Let state = reactive({count: 0}); If () => state is invalid, or {deep: true} watch(() => state.count, (val, old) => {console.log(old, val); }); // add {deep: true} watch(() => state, (val, old) => {console.log(old, val); }, { deep: true } ); // Listen on the whole object, the old and new values are the same, //state => _. CloneDeep (state) watch(state, (val, old) => {console.log(old.count, val.count); });Copy the code

It is also possible to listen on more than one parameter at a time, using an array of two parameters respectively, personally or recommend a single:

const state = reactive({ count: 1 }); const count = ref(0); Watch ([() => state.count, count], ([newState, newCount], [oldState, oldCount]) => {console.log("new:", newState, newCount); console.log("old:", oldState, oldCount); });Copy the code

If you add immediate: true, the initialization will be performed.

watchEffect

It “immediately executes” a function passed in, tracing its dependencies responsively, and reruning the function when its dependencies change:

const state = reactive({ count: 1 }); const count = ref(0); watchEffect(() => { if (state.count > 3) { count.value++; }}); watchEffect(() => console.log(count.value));Copy the code

As for the watch and watchEffect sharing of stopping listening, the removal of side effects (with onInvalidate being passed in as the third argument to the callback accordingly), side refresh timing, and listener debugging behavior need to be studied carefully.

computed

Since VUe2, many people have been confused about when to use computed and when to use watch. Computed is mainly used to declare that there are two or more dependent data, that is to say, a variable is judged according to multiple data, computed and watch are used separately. Not to mention the syntax differences, vue3’s computed common syntax is a function with a return and can have more than one at a time:

let count = ref(0);
let page = ref(0);
let pg = computed(() => {
  return count.value + page.value;
});
Copy the code

Note that computed declared variables (PG) cannot be modified directly (read only), and have get and set functions (read and write), just like VUe2.

DefineProps, defineEmits

The defineProps and defineEmits APIS must be used in single-file components to declare props and emits, which can be considered syntactic sugar. The parent component passes the value as before, and the child component receives:

<div class="home"> <input V-model =" MSG "/> <HelloWorld: MSG =" MSG" @change="change" /> </div> </template> <script lang="ts" setup> import { ref } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; let msg = ref("is parent"); const change = (val: string) => { msg.value = val; }; </script> // sub-component <template> <div>{{MSG}}</div> < button@click ="change">emit</button> </template> <script lang="ts" setup> import { defineProps, defineEmits } from "vue"; const props = defineProps({ msg: String, }); console.log(props.msg); const emit = defineEmits(["change"]); const change = () => { emit("change", "is son"); }; </script> // Set the default value defineProps({MSG: {type: Number, default: 100,},});Copy the code

Template can be used directly with MSG, which is called props. MSG.

withDefaults

DefineProps only restricts types and does not provide default values. To solve this problem, the withDefaults compiler macro is provided:

type Porps = {
  msg: string;
};
const props = withDefaults(defineProps<Porps>(), {
  msg: "default",
});
Copy the code

WithDefaults takes two arguments. The first argument is a generic of the defineProps + props field. The second field is the default and can be left unset.

You can also listen to props:

watch( () => props.msg, (val) => { console.log(val); });Copy the code

this.$refs

Vue2 still needs this API in many cases, but vue3 is more specific. To get a reference to an element or component instance within a template, we can declare ref as usual, expose root in the render context, and bind it to a div as its ref with ref=”root”. In the virtual DOM patching algorithm, if the REF key of a VNode corresponds to the REF in the rendering context, the corresponding element or component instance of a VNode will be assigned to the value of that REF. This is done during the virtual DOM mount/patch process, so the template reference only gets assigned after the initial rendering.

<button ref="testRef">testRef</button> let testRef = ref(null); OnMounted (() => {// DOM elements will be assigned to ref console.log(testref.value) after initial rendering; // <button>testRef</button> });Copy the code

nextTick

Same as vue2:

nextTick(() => {
  console.log(testRef.value);
});
Copy the code

We can also use the async function await as provided in the official website:

let testRef = ref(null);
const nextTickFn = async () => {
  await nextTick();
  console.log(testRef.value);
};
nextTickFn();
Copy the code

defineExpose

Vue2 sometimes calls child component functions or variables with this.$refs. Single-file components are turned off by default, so single-file components are exposed using the defineExpose compiler macro:

// Parent component <template> <div class="home"> <HelloWorld ref="sonRef" /> </div> </template> <script lang="ts" setup> import { nextTick, ref } from "vue"; import HelloWorld from "@/components/HelloWorld.vue"; let sonRef = ref(); nextTick(() => { sonRef.value.sonFn(); console.log(sonRef.value.sonRef); }); </script> // subcomponent let sonRef = ref("is son"); const sonFn = () => { console.log("is son fn"); }; defineExpose({ sonFn, sonRef });Copy the code

Vue2 implements this.$parent in a single file component, but the code is not given directly:

//父组件
const parentRef = ref("is parent ref");
const parentFn = () => {
  console.log("is parent fn");
};
defineExpose({
  parentRef,
  parentFn,
});

//子组件
let parent = getCurrentInstance();
console.log(parent?.parent?.exposed?.parentRef.value);
parent?.parent?.exposed?.parentFn();
Copy the code

The new component

teleport

The main function of this component is that it can be detached from the fixed position of the component, and can be mounted to the logical optimal position. Other uses are the same as the component, only the position changes:

<teleport to="#teleportDiv">
  <HelloWorld />
</teleport>

<teleport to="body">
  <HelloWorld />
</teleport>
Copy the code

The mounted elements are parsed from the top down, the first to element, tag, class, ID, and so on. You don’t use it casually, you use an ID element or a body element.

Suspense

Suspense is an experimental new feature and officially not for production. The main idea is to allow component asynchronously processed waiting processes to be promoted into the component tree.

The top await inside the single-file component says that async Setup () must be combined with Suspense, which is still an experimental feature. We intend to develop and document it in a future release.

So I won’t show you code implementations that aren’t single-file components.

The life cycle

The life cycle is the same as before, but with on, destroy, unmount. Setup is executed before beforeCreate and Created, instead of beforeCreate and Created.

  • beforeCreate –> beforeCreate
  • created –> setup
  • beforeMount –> onBeforeMount
  • mounted –> onMounted
  • beforeUpdate –> onBeforeUpdate
  • updated –> onUpdated
  • beforeDestroy –> onBeforeUnmount
  • destroyed –> onUnmount

Use:

onMounted(() => {
  console.log("mounted");
});
Copy the code

I tried, and I can write more than one.

It is not necessary to remember all the new or removed apis of Vue3. If some apis are not effective, check the official website again. Of course, the basic apis should be noted down.

Still the same words, first learn the basics, start development, and then slowly to understand the study of uncommon, even source code.

Welcome to subscribe to coding personal notes