Vue3
[TOC]
learning
Motivation for vuE3 rewrite
-
Use new JS native features
-
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:
- 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
- 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
- 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
- Listen for reactivity data for ref declarations
- Listen for reactive data on reactive statements
- 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 vue2
this.$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
- Setup’s onMounted execution precedes the mounted of the entire component
- OnMounted execution of setup follows execution of the Setup synchronization component
- 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
- 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
- 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
-
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.
-
Reactive data created by the ref() function can be accessed in a Reactive object.
-
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:
- with
reactive()
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;- with
ref()
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:
- delete
tag
Prop – Uses scope slots instead - delete
event
Prop – Uses scope slots instead - increase
scoped-slot
API - Stop automatic transfer
click
Events are assigned to internal anchor points - add
custom
Prop to fully support customrouter-link
Apply 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