Vue3

[TOC]

learning

Motivation for vuE3 rewrite

  1. Use new JS native features

  2. Resolve design and architectural defects

    A proxy for ES6 was added to VUe3, which eliminates all of vue2’s limitations (such as the addition of new object attributes, and the fact that direct changes to array elements do not trigger reactive mechanisms, which many novices call bugs) and provides better performance.

    Proxy is the real meaning of an object package on a layer of Proxy to perform data interception hijacking operations, so overall this complexity is directly reduced by an order of magnitude. As long as you access or modify the object after the proxy is aware of this layer of proxy to dynamically decide what to return to you, and there is no need to repeatedly attach the selected items to the component instance’s this. Because you have this information when you’re accessing something, whether it’s props or Data or something else, the VUE just takes that information out of the corresponding data structure, and you can feel that the memory usage of the component has been cut in half.

Improvements and features of VUE3

1. Performance improvement: 41% reduction in package size, 55% faster initial rendering, 133% faster update, 54% reduction in memory usage.

2. The new Composition API makes components easier to maintain and reduces unwanted data binding pages.

4. Better TypeScript support, which can be configured directly in the create command for seamless page integration.

5.Teleport(transient components), Suspense(solve asynchronous component loading problems) and global API modification and optimization.

6.Vue3 is compatible with most of the features of Vue2, and can be developed with Vue2 code.

New point in vue3.x

1. Multi-node components

In VUE3, components officially support multi-node components, known as fragments!

2.setup

To start using the Composition API, we first need a place where we can actually use it. In Vue components, we call this location setup.

Setup execution does not create a component instance, so you cannot use this, which is undefined. Cannot access any data, computed, or methods declared in the component except props.

Note: Setup is designed to optimize performance by introducing global unification on demand

Parameters (props, context)
// The parent component passes the props to be reactive (updated automatically when new props are passed).
// context {attrs, emit, slots}
setup(props, context) {
    console.log(context)
    /** * attrs: Proxy * emit: (event, ... args) => instance.emit(event, ... args) * slots: Proxy */
}
Copy the code
Setup lifecycle hooks
Hook function Setup a hook
beforeCreate There is no
created There is no
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered

Because setup runs around beforeCreate and Created lifecycle hooks, you don’t need to explicitly define them. In other words, any code that should be written in these hooks should be written directly in the Setup function.

Usage:
<template> <div class="home"> {{ name }}</div> <ul> <li v-for="item in list" :key="item" @click="show(item)">{{ item }}</li> </ul> </div> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; Export default defineComponent({name: "Home", components: {}, props:[' MSG '], setup(context) {// The setup function is a function between the life cycle beforeCreate and Created hook functions, so it is not possible to use data and methods in the setup function. Methods, etc., can use data returned from setup. /* the first argument to the function is props, for receiving props. MSG This is a responsive Proxy object that cannot be deconstructed because it will not respond. ToRefs let {MSG} = toRefs(props) // But if ref = msg.value, props Emit Because there is no Vue instance created in the setup function, it is not possible to use vm.$attrs, vM. $slots, and vM. $emit, so these attributes are used in the same way. Note: Context. attrs and vm.$attrts contain attributes (except class and style) that are not recognized by the declaration in the instance vm.props. So variables exposed in props in setup() are not exposed in context.attrs. Context. Slots and vm.$slots can only access named slots. Unnamed slots or v-slot:default are not exposed. Attrs and slots for context are stateful and update in real time when components are updated, so don't deconstruct them either. Unlike props, however, they are not reactive, and their use in setup() should remain read-only, and if changed can be done in the periodic function onUpdated. Context. emit and vm.$emit can trigger listening events on instances. */ const list = ref([" s0 ", "s0 "]); const name = ref(""); Const show = (index: string) => {name. Value = index; // const show = (index: string) => {name. }; // Note: The template cannot be used without returning data. return { list, name, show }; }}); </script>Copy the code
Reactive (
<template> <div class="home"> {{ data.name }}</div> <ul> <li v-for="item in data.list" :key="item" @click="data.show(item)">{{ item }}</li> </ul> </div> </template> <script lang="ts"> import { defineComponent, reactive } from "vue"; export default defineComponent({ name: "Home", components: {}, setup() { const data = reactive({ list: [" shenzhen ", "Beijing", "Shanghai"], name: "", show: (index: string) = > {data. The name = index; }}); return { data }; }}); </script>Copy the code
Usage three: toRefs() optimization
<template> <div class="home"> {{ name }}</div> <ul> <li v-for="item in list" :key="item" @click="show(item)">{{ item }}</li> </ul> </div> </template> <script lang="ts"> import { defineComponent,reactive,toRefs } from "vue"; export default defineComponent({ name: "Home", components: {}, setup() { const data = reactive({ list: [" shenzhen ", "Beijing", "Shanghai"], name: "", show: (index: string) = > {data. The name = index; }}); const refData = toRefs(data); // Can not be directly resolved... Data must be returned with toRefs() {... refData }; }}); </script>Copy the code

jsx

setup() {
    const root = ref(null)
    return () = > <div ref={root} />
}
Copy the code
Get the method for sample this in Setup

Setup this points to window, and the composition document doesn’t say how to get the component instance.

We can get the component instance via getCurrentInstance() :

setup() {

  // getCurrentInstance() gets the component instance

  const instance = getCurrentInstance()

  console.log(instance);

  onMounted(() = >{

    // The context of the component instance is the familiar this

    console.log(instance.ctx.foo); // 'foo'

    console.log(instance.ctx.bar()); // 'I am a bar method'

  })

  return{}},Copy the code

However, we soon get confused. This component instance is not like this. If we access this.foo directly, we still don’t find the data.

The component instance structure in VUe3 is as follows, and this in each option is actually CTX or proxy

If you look closely at CTX, you will find that it is not a Proxy object, that is, it has only values but no responsiveness. Therefore, if you want to make use of responsiveness, you will need to use the Proxy property to return the context object. If you only want data, there is a data that is also a Proxy.

setup() {

  const { proxy, data } = getCurrentInstance()

  // To take advantage of responsiveness, use the proxy context

  watchEffect(() = > {

    console.log(proxy.foo) // Foo changes will have output

    console.log(data.foo) // Foo changes will have output})},Copy the code

Finally, note that setup() is executed at a very early point in time, even before created, so foo and bar access would be missing if it were not specifically placed inside onMounted.

setup() {

  const instance = getCurrentInstance()

  console.log(instance.ctx.foo); // undefined

  console.log(instance.ctx.bar()); // undefined

},
Copy the code

Common solutions:

What if setup function is too long?

setup(){

  let { val, todos, addTodo } = useTodo()

  let {count,double,add} = useCounter() 

  let {x, double:doubleX} = useMouse()

  return {

    val, todos, addTodo,

    count,double,add,

    x,doubleX

  }

}
Copy the code

The return context is too long. We can use vue3 setup script to optimize the setup configuration and export each function once

<script setup>

import useCounter from './counter'

import useMouse from './mouse'

import useTodo from './todos'



let { val, todos, addTodo } = useTodo()

export {val, todos, addTodo}



let {count,double,add} = useCounter()

export {count,double,add}



let {x, double:doubleX} = useMouse()

export {x,doubleX}

</script>
Copy the code

Why is my property not responding

Here is the code I wrote for the first time

setup({ foo, bar }) {

  watchEffect(() = > {

    console.log(foo, bar) // Foo, bar changes, no output})}Copy the code

Props is a Proxy object, and when you deconstruct it, it becomes unresponsive, so be gentle with props and don’t split it

setup(props) {

  watchEffect(() = > {

    console.log(props.foo, props.bar) // foo, bar changes, output})}Copy the code

You can split it if you want. How do you like it

setup(props) {

  const { foo, bar } = toRefs(props)

  watchEffect(() = > {

    console.log(foo.value, bar.value) // foo, bar changes, output})}Copy the code

How to send custom events?

$emit() this.$emit() will emit events on this.

It is possible to distribute events via component instances, such as:

setup() {

   getCurrentInstance().emit('ooxx')}// But this is a bit tricky, so we use the second argument to the setup function:

setup(props, ctx) {

              ctx.emit('ooxx')}// Emit can also be destructed directly to make it easier to use:

setup(props, { emit }) {

              emit('ooxx')}Copy the code

Vue3 gets the route of the current page

import { getCurrentInstance } from 'vue'

setup() {
  const { ctx } = getCurrentInstance()
  console.log(ctx.$router.currentRoute.value)
}
Copy the code
import { useRoute } from 'vue-router'
import { toRaw } from 'vue'

setup () {
  const route = useRoute()
  console.log(toRaw(route))
}
Copy the code

The parent component calls the child component method

/ / the parent component
  <Listmodify :isShow="isShow" ref="child"></Listmodify>
  
  setup(props, context) {
        const child = ref();
        const handleEdit = () = > {
          child.value.str();
        };
         return {  handleEdit,  child };
  }


/ / child component
  setup(props, context) {
        const str = () = > {
      console.log("I got called by the parent component.");
    };
         return {  str };
  }
  
Copy the code

3. Teleport

(Do not mount to app to solve style conflicts)

Teleport provides A way to control which parent object in the Dom renders HTML without resorting to global state or splitting it into two parts.

The use of the Teleport

Example 1:

1. Build a VUE3 project first

2. Start using examples:

 <div id="app"></div>
 <div id="teleport-target"></div>
 <div id="modal-container"></div>
Copy the code
  <button @click="showToast" class="btn">Open the toast</button>
  <! The to attribute is the target position -->
  <teleport to="#teleport-target">
    <div v-if="visible" class="toast-wrap">
      <div class="toast-msg">I am a Toast writer</div>
    </div>
  </teleport>
Copy the code
import { ref } from 'vue';
export default {
  setup() {
    // Toast encapsulation
    const visible = ref(false);
    let timer;
    const showToast = () = > {
      visible.value = true;
      clearTimeout(timer);
      timer = setTimeout(() = > {
        visible.value = false;
      }, 2000);
    }
    return {
      visible,
      showToast
    }
  }
}
Copy the code

3. Use with Vue Components — Modal-wrapped components

<div id="app"></div>
  <div id="teleport-target"></div>
   <div id="modal-container"></div>
  <script type="module" src="/src/main.js"></script>
Copy the code
<teleport to="#modal-container">
    <! -- use the modal component, pass in the prop -->
    <modal :show="showModal" @close="showModal = false">
      <template #header>
        <h3>custom header</h3>
      </template>
    </modal>
  </teleport>
Copy the code
import { ref } from 'vue';
import Modal from './Modal.vue';
export default {
  components: {
    Modal
  },
  setup() {
    // Encapsulate Modal
    const showModal = ref(false);
    return {
      showModal
    }
  }
}
Copy the code

In this case, even if Modal is rendered in a different place, it will still be a child of the current component (the component that invokes Modal) and will receive show Prop from it

Example 2:
  1. Add a new insertion point to the index.html page (it will be mounted under the #headTitie DOM)
<div id="headTitie"></div>

<div id="app"></div>
Copy the code
  1. Create a new headtitle. vue in the Components directory
<template> <teleport to="#headTitie"> <div class="head"> <h1>{{ title }}</h1> </div> </teleport> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; Export default defineComponent({name: "headTitie", setup() {const title = ref("Vue3 new feature example "); return { title, }; }}); </script>Copy the code
  1. In the App. Vue
<template>
  <headTitle />
  <router-view />
</template>

<script lang="ts">
import headTitle from "./components/headTitle.vue";
    
export default {
  name: "App",
  components: {
    headTitle,
  },
};

</script>
Copy the code

4. Watch to monitor

Introducing a watch from vUE can be seen in point 4: Reactivity

  1. Listen for reactivity data for ref declarations
  2. Listen for reactive data on reactive statements
  3. Listen to the data in props
<script>
// Must be used before introduction
import {ref, watch} from 'vue'
setup(props) {
    // listen for ref data
    let count = ref(0)
    watch(count, (val, old) = > {
        // New data, old data
    })
    
    // Listen to reactive data objects
    let person = reactive({
        age: 18
    })
    watch(() = > person.age, (val, old) = > {
        // New data, old data
    })
    // Listen to reactive data arrays
    let arr = reactive([1.2.3])
    watch(arr, (val, old) = > {
        // New data, old data
    })
    
    // Props passes a testkey to props
    watch(() = > props.testkey, () = >{})// Pay attention to return
	return {
	    count,
	    person,
	    arr
	}
}
</script>

Copy the code
<script lang="ts"> import { defineComponent, ref, reactive, toRefs, watch } from "vue"; Export default defineComponent({name: "Home", Components: {}, setup() {const text = ref(" test single value "); Const data = reactive({list: [" 表 ", "表 "," 表 "], show: (index: string) => {data.name = index; }}); //watch([text,()=>data.name]) () = > data. The name to compatible vue2 watch ([text, () = > data. The name], (newValue, oldValue) = > {the console. The log (` new - > ${newValue} `); console.log(`old--->${oldValue}`); }); const refData = toRefs(data); return { ... refData, }; }}); </script>Copy the code

What’s the difference between watchEffect and Watch?

These two methods are very similar in that they both observe responsive data and perform side effect functions, but they have the following differences:

  • Watch needs to explicitly specify monitoring targets
watch(() = > state.counter, (val, prevVal) = > {})

/ / watchEffect don't need

watchEffect(() = > {

console.log(state.counter)

})
Copy the code
  • Watch can get the value before and after the change
  • Watch is lazily executed and is equivalent to vue2this.$watch()In order to collect dependencies, the watchEffect is executed immediately

Can I write more than one lifecycle hook?

Of course you can write more than one, and they will be executed in the order they were registered:

setup() {

  onMounted(() => {})

  onMounted(() => {})

  onMounted(() => {})

}
Copy the code

You can even split multiple hooks of the same lifecycle into separate functions

function fun1() {

  // Use onMounted to execute the code

  onMounted(() = >{})}function fun2() {

  // It is also possible to execute code with onMounted

  onMounted(() = >{})}setup() {

  fun1()

  fun2()

  onMounted(() = >{})}Copy the code

5. Computed attributes

Introduce computed from VUE

<script>
import {ref, computed} from 'vue'
setup(props) {
    let count = ref(0)
    
    // The calculated properties of the current component
    let countCom = computed(() = > {
        return count.value * 2
    })
    //props to pass in the calculation property
    let countCom2 = computed(() = > {
        return props.propsKey * 2
    })
}
</script>
Copy the code

Extension –

  • Computed Creates read-only computing properties

Passing a function to computed() yields a read-only computed property:

Const count = ref(1) Make its value 1 greater than count const bigCount = computed(() => count.value + 1) console.log(bigcount.value) // Output 2 bigcount.value ++ // The error is to writeCopy the code
  • Computed To create readable and writable compute properties
Const count = ref(1) // Create a computed property and pass in an object const bigCount = computed({// get: () => (count. Value + 1), // set: Val => {count. Value = val - 1}}) The count value is updated console.log(count.value) // 8Copy the code

6. Setup lifecycle hook usage

  1. Setup’s onMounted execution precedes the mounted of the entire component
  2. OnMounted execution of setup follows execution of the Setup synchronization component
  3. Setup onMounted and setup cannot use this
<script>
import {onMounted} from 'vue'
mounted () {
    console.log(4)
},
setup () {
    onMounted(() = > {
        console.log(1)})console.log(2)
    setTimeout(() = > {
        console.log(3)},0)
    // Print order
    // 2, 1, 4, 3
    
    
    onMounted(() = > {
        console.log(this)})/ / print
    //undefined
}
</script>
Copy the code

7. Dojo.provide and inject

Import parent component provide from VUE

<script>
import {provide} from 'vue'

export default {
    setup () {
        provide('person', {
            name: 'Bob'.age: 18
        })
        provide('city'.'hangzhou')
    }
}
</script>
Copy the code

Descendant component Core

<script>
import {inject} from 'vue'

export default {
    setup () {
        // Data provided by parent components
        let person = inject('person')
		let city = inject('city')
		// The parent component does not provide a value, give a default value is not given default is undefined and there will be Vue warn warning
		let noProvide = inject('noProvide'.'noProvide hah')
    }
}
</script>
Copy the code

Provide reactive data parent component value changes and descendant component values change accordingly

<script>
import {provide} from 'vue'

export default {
    setup () {
        let city = ref('binjiang')
        provide('city', city)
    }
}
</script>
Copy the code

Provide a function

<script>
import {provide} from 'vue'

export default {
    setup () {
        let provideFun = () = > {
            console.log('provide fun')
        }
        provide('provideFun', provideFun)
    }
}
</script>
Copy the code
/ / the parent component
import { ref,provide } from 'vue';
// provide() accepts two parameters (name: string,data: passed data)
setup(){
	let init = ref(1);
	function change(){
       init.value += 1
    }
    provide('init',init) 
    provide('update',change) // The key to data responsiveness is that the method to modify the data should also be passed along, otherwise it will not respond
    return {
       change,init
    }
}
/ / child component
import { inject,readonly } from 'vue';
Inject () Receives two parameters (name: the name to be provided,data: optional, default data).
setup(){
    const oneInit = inject('init') // Receive data from above
    const updateUser = inject('updatea1',readonly(oneInit))
    // Receive method, readonly read-only, in case the data is modified for external reasons
    return {
            oneInit,
            updateUser
        }
}
Copy the code

8.Reactivity

One of Vue’s most unique features is its unobtrusive reaction system.

When you pass a pure JavaScript object to an application or component instance as a data option, Vue will iterate over all of its properties and convert them to Proxies using handlers with getters and setters

  • Trace the function that changes it: effect this operation in the getter of the agent
  • Trigger the function so that it can update the final value: operate trigger in the setter in the agent
Declare reactivity data

Ref, Reactive, and Readonly are commonly used to declare data

  • Ref declares the base type
  • Reactive declares the reference type
  • Readonly Specifies the read-only reference type
import { ref, reactive, readonly } from 'vue'

export default {
    setup () {
        // use ref to declare basic types
        // Use reactive to declare a reference type
        let count = ref(0) // Use count.value on script and {{count}} on template.
        let state = reactive({
            name: 'Bob'
        }) // Use state.name in script and {{state.name}} in template.
        
        // declare the reference type with ref
        let obj1 = ref({
			count: 1
		})
		// use reactive to declare basic type warnings ⚠️ can be used normally, but is not reactive
		let num1 = reactive(10) //value cannot be made reactive: 10
		
		// readonly
		// Readonly is the same as reactive, but only declares read-only data
		let person = readonly({age: 18})
		setTimeout(() = > {
		    // Timer modification warning ⚠️
			person.age = 10 // Set operation on key "age" failed: target is readonly
		});
		
        // Return must be used elsewhere in template and script
        return {
            count, 
            state,
            obj1
        }
    }
}
Copy the code

Count Indicates the printed data

RefImpl {_rawValue: 0._shallow: false.__v_isRef: true._value: 0}
    __v_isRef: true
    _rawValue: 0
    _shallow: false
    _value: 0
    value: 0
Copy the code

State Indicates the printed data

Proxy {name: "Bob"}
    [[Handler]]: Object
        deleteProperty: ƒ deleteProperty (target, key)getƒ (target, key, receiver)has: ƒ has (target, key)ownKeys: ƒ ownKeys (target)setƒ (target, key, value, Receiver) [[target]]:Object
        name: "Bob"
    [[IsRevoked]]: false
Copy the code

Obj1 Prints the data

RefImpl {_rawValue: {... },_shallow: false.__v_isRef: true._value: Proxy}
    __v_isRef: true
    _rawValue: {count: 1}
    _shallow: false
    _value: Proxy {count: 1}
    value: Proxy
        [[Handler]]: Object
        [[Target]]: Object
            count: 1
        [[IsRevoked]]: false
Copy the code

Num1 Indicates the printed data

10
Copy the code
The template used in
<! -- Use basic types defined by ref directly --> <! Direct reference types defined by Reactive. Corresponding properties --><div class="vue3_pro">
	count: {{count}}
	state: {{state.name}}
</div>
Copy the code

9. Vue3 lifecycle function usage

Need to introduce (note: vue2 life cycle function does not affect)

<script lang="ts"> import { defineComponent,ref,reactive,toRefs, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured, onRenderTracked, onRenderTriggered } from "vue"; Export Default defineComponent({name: "Home", Components: {}, setup() {//setup() is executed before beforeCreate and created to start creating components. Const data = reactive ({list: [" shenzhen ", "Beijing", "Shanghai"]}); OnBeforeMount (()=>{// Function executed before the component is mounted to the node. }) onMounted(()=>{// Function executed after the component is mounted. }) onBeforeUpdate(()=>{// Function executed before component update}) onUpdated(()=>{// Function executed after component update is complete. }) onBeforeUnmount(()=>{// Function executed before component unmounts. }) onUnmounted(()=>{// Function executed after the component is unmounted. }) onActivated(()=>{// The component contained in <keep-alive> will have two more lifecycle hook functions. Executed when activated. }) onDeactivated(()=>{// Switch from component A to component B when component A disappears. }) onErrorCaptured(()=>{// Activate the hook function when you catch an exception from a descendant component. }) //< debug onRenderTracked((event)=>{// Tracks all states firing console.log(event); }); OnRenderTriggered ((event) => {console.log(event); //oldValue oldValue //target current page response variables and functions}); /> const refData = toRefs(data); return { ... refData }; }, mounted(){console.log("vue2 lifecycle "); }}); </script>Copy the code

10.Vue3 modular reuse (optimize mixins)

1. Create the usetime. ts file

import { ref } from "vue";
const time = ref("00:00:00");
const getTime = () = > {
    const now = new Date(a);const h= now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
    const m = now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
    const s= now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
    time.value = h + ":" + m + ":" + s;
    setTimeout(getTime, 1000);
};
export { time, getTime }
          
Copy the code

2. The introduction of

<template> <div class="home"> {{time}} < button@click ="startTime"> start </button></div> </template> <script lang="ts"> import {defineComponent, ref } from "vue"; import { time, getTime } from './useTime'; export default defineComponent({ name: "Home", components: {}, setup() { const startTime = () => { getTime(); }; return { startTime, time }; }}); </script>Copy the code

Suspense Asynchronous request components

  1. A new Demo. Vue
<template> <div class="Demo"> {{ name }}</div> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; export default defineComponent({ name: "Demo", components: {}, setup() { return new Promise((resolve, reject) => { setTimeout(() => { return resolve({ name: "I am Suspense asynchronous request component"}); }, 2100); }); }}); </script>Copy the code
  1. Use the import home.vue
< the template > < div class = "home" > < Suspense > < # default template > < Demo / > < / template > < # template fallback > < p > loading... </p> </template> </Suspense> </div> </template> <script lang="ts"> import { defineComponent } from "vue"; import Demo from "./Demo.vue"; export default defineComponent({ name: "Home", components: {Demo} }); </script>Copy the code

Composition – Api:

12.ref()

The ref() function creates a reactive data object based on a given value. The return value is an object containing only a.value attribute.

  • Create a reactive object with ref
/ / into the ref
import { ref } from '@vue/composition-api'

setup() {
    // Create a responsive object
    const count = ref(0);

    return {
        count
    }
}
Copy the code
  • Use reactive objects
<p> {{count}}</p> <button @click="count++">Copy the code

To change this value in JS, add an additional value:

  • Precautions for ref
  1. In the setup() function, the reactive data created by ref() returns objects, so it needs to be accessed with.value;

    Outside the setup() function, you don’t need.value, just access it.

  2. Reactive data created by the ref() function can be accessed in a Reactive object.

  3. The new ref() overwrites the old ref().

Ref data response listening, and react-hook seems similar. The ref function passes in a value as an argument and returns a responsive REF object based on that value, which is tracked whenever its value is changed or accessed. Just like in our modified example code, changing the count.value value triggers a re-rendering of the template to display the latest value

13.reactive()

Reactive is used to define more complex data types, but the variables are no longer reactive Ref object data

Reactive () takes a normal object and returns a reactive object.

In vue2.x, we only need to define a data in data() to make it reactive. In Vue3.0, reactive data is created using reactive functions such as Reactive or ref.

  • Create reactive objects using Reactive
// Add Reactive to the component library
import { reactive } from '@vue/ composition-api'

setup() {
    // Create a responsive object
    const state = reactive({
        count:0
    });

    // Return the reactive object and expose it to the template
    return state;
}
Copy the code
  • Use reactive objects
<p> <button @click="count++">Copy the code

Composition-api introduces a stand-alone data-responsive method reactive, which handles incoming objects in a reactive manner:

const state = reactive({

  foo: 'foo',

})

watchEffect(() = > {

  console.log(state.foo)

})

state.foo = 'foooooo' / / output 'foooooo'
Copy the code

This approach, similar to the data option we set up, solves most of our requirements. But there are also the following problems:

  • When we export the state directly, we prefix the state in the template
setup() {

const state = reactive({})

return { state }

}

<div>{{ state.foo }}</div>


// toRefs is introduced to solve this problem

setup() {

const state = reactive({})

return { ...toRefs(state) }

}

<div>{{ foo }}</div>
Copy the code

The choice between REF and Reactive

For single-valued objects, ref is recommended, even for single-valued objects

A business concern has multiple values, and reactive is recommended

14. readonly()

Pass in a reactive object, plain object, or ref, and return a read-only object proxy. The proxy is deep and the data inside the object is read only.

const state = reactive({ count: 0 })

const copy = readonly(state)

watchEffect(() = > {
  // Rely on tracing
  console.log(copy.count)
})

// Changes on state trigger listening on copy
state.count++

// The read-only attribute cannot be modified
copy.count++ // warning!
Copy the code

15. watchEffect()

WatchEffect () executes the incoming function immediately, listens for its dependencies in a responsive manner, and rerunts the function when its dependencies change.

  • Basic usage
const count = ref(0)

// Print 0 for the first time
watchEffect(() = > console.log(count.value))

setTimeout(() = > {
  // The monitored data changes, triggering the function to print 1
  count.value++
}, 1000)
Copy the code
  • Stop listening

WatchEffect () returns a function when used, and stops listening when the returned function is executed.

const stop = watchEffect(() = > {
  / *... * /
})

// Stop listening
stop()
Copy the code

Composition-api depends on tools

1. isRef()

IsRef (), as its name implies, is the value that determines whether a value is a response created by ref().

It is used when you need to expand a reactive value that might be created for ref() :

import { isRef } from '@vue/composition-api'

const unwrapper = isRef(foo) ? foo.value : foo
Copy the code

2.toRefs()

ToRefs () converts reactive objects created by Reactive () into normal objects with ref-reactive values

Before we understand the use of toRefs(), we need to understand the difference between reactive() and ref() objects:

  1. withreactive()Create a reactive object, the whole object is reactive, and each item in the object is a normal value. When you expand it with the expansion operator, the normal value of the whole object is not reactive;
  2. withref()Reactive values created are themselves reactive and do not depend on other objects.

So when you need to expand reactive objects created by Reactive () without making them less reactive, you need toRefs() to transform them:

mport { toRefs } from '@vue/composition-api'

setup() {
    // Define reactive data objects
    const state = reactive({
        count: 0
    })

    // Define a simple function that makes count +1 each time
    const add = () = > {
        state.count++
    }

    // Return the contents of the setup function for external use
    return {
        // Expand state and convert its attributes to reactive data in the form of ref. toRefs(state), add } }Copy the code
<template>
    <div>
        <p>The current count value is: {{count}}</p>
        <button @click="add">Click on the + 1</button>
    </div>
</template>
Copy the code

Changes of VUe3 and VUe2

This is all a trial run

router-link

The improvements are as follows:

  • deletetagProp – Uses scope slots instead
  • deleteeventProp – Uses scope slots instead
  • increasescoped-slot API
  • Stop automatic transferclickEvents are assigned to internal anchor points
  • addcustomProp to fully support customrouter-linkApply colours to a drawing

In vue2-router, to render

into some kind of tag, such as

<router-link ="/" tag="button"> </router-link>! <button> </button>Copy the code

You may need to do this later:

<router-link
  to="/foo"
  v-slot="{ href, route, navigate, isActive, isExactActive }"
>
  <li
    :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']"
  >
    <a :href="href" @click="navigate">{{ route.fullPath }}</a>
  </li>
</router-link>
Copy the code

The object of slot prop contains the following properties:

Href: the parsed URL. Will be the href attribute of an A element. 2. Route: normalized address after parsing. Navigate: the function that triggers the navigation. Automatically blocks events when necessary, as with router-link. IsActive: True if the active class needs to be applied. Allows an arbitrary class to be applied. IsExactActive: True if exactactive classes need to be applied. Allows an arbitrary class to be applied.

API changes

Note about the Composition API:

UseRouter 2 useRoute 3 onBeforeRouteLeave 4 onBeforeRouteUpdate 5 useLink