In order to be able to use the Composition API, we need to have a place where we can actually use it. In the VUE component, we refer to this location as setup
The setup function
The setup function is executed before the component is created, and the props in the setup function, once resolved, serve as the entry to the Composition API
Note: We can’t use this in the setup function because it won’t find the component instance. The reason is that although the component instance is created before the setup is performed, data,computed,methods, etc., are not resolved before the setup function is called, so they cannot be retrieved in the setup.
Setup takes two parameters (props,context)
props
As the first argument in the setup function, the props is responsive and will be updated when a new prop is passed in
Properties passed by the parent component will be put into the props object
- The type of props is defined in the props option object, as in Vue2
- The template is still written the same way
- Because props are passed directly as arguments to the setup function, we can use them directly as arguments.
export default {
props: {message: {type:String.default:"hello"}},setup(props){
consloe.log(props.message)
}
}
Copy the code
!!!!! Due to theprops
It’s responsive, so we can’t use deconstruction, which would eliminate the responsiveness of props.
If you need structural props, then you need to use the toRefs function to complete the operation.
import {toRefs} from 'vue'
setup(props){
const message = toRefs(props,'message')
console.log(message.value)
}
Copy the code
context
As the second argument to the setup function, the context is a plain JavaScript object that exposes the component’s three properties
- **attrs ** : all non-prop attributes
- Slots: slots passed from the parent component
- Emit: emit when we need to emit events internally. It is the same as this.$emit in vuE2
!!!!! Since the context is just a normal JavaScript object, it is not responsive, which means that we can safely comparecontext
Use deconstruction
export default{
setup(props,{attrs,slots,emit}){... }}Copy the code
The return value of the setup function
Since setup is a function, it should return a value
If the return value of setup is an object, then the property of that object is accessible in the template.
Note that refs returned from setup are automatically shallowly unpacked in the template, so there is no need to use.value in the template
Apis for responsiveness
reactive
Returns a responsive copy of the object
If you want to define data that is reactive in your setup, you can use reactive
const state = reactive({ name:'wangpf'.age:18 })
Copy the code
Why is it that reactive makes it reactive?
- Because when we use the reactVie function to process our data, the data will be used again for dependency collection
- All the dependencies collected are reactive operations on the object when the data changes
- In fact, in VUE2, the data option that we write is given internally
reactive
Function to turn it into a reactive object
Two points to note:
-
Reactive will unpack all deep refs while maintaining the refs’ responsiveness
const count = ref(0) const obj = reactive({ count }) // Ref will be unpacked console.log(count.value === obj.value) // true // Update to 'obj.count' count.value++ console.log(count.value) / / 1 console.log(obj.count) / / 1 // Update to ref 'count' obj.count++ console.log(count.value) / / 2 console.log(obj,value) / / 2 Copy the code
-
When the REF is allocated to reactive, it will automatically unpack
const count = ref(1) const obj = reactive({ }) obj.count = count console.log(obj.count) / / 1 console.log(obj.count === count.value) // true Copy the code
But because reactive is limited to the type we pass in, it requires that we pass in an object or an array
If we pass in a basic data type (String,Number,Boolean), we will get a warning.
In this case, we can use another API,ref
ref
Accepts an internal value and returns a responsive and variable REF object. The ref object has a single property (.vlaue) that points to an internal value
Ref returns a mutable responder object that maintains its internal value as a responder reference.
The internal values are maintained in the Vlaue attribute of the REF
readonly
We can get a reactive object by using reactive or ref, but in some cases we pass in a reactive object that we want to use somewhere else, but can’t be modified, we can use readonly
Readnoly returns a read-only proxy for a native object by hijacking it in the set method using the set in the proxy, and setting the value cannot be modified
API on reactive judgment
isProxy
Check whether the object is a proxy created by reactive or readonly
const state = reactive({ count : 0 })
const count = 0
isProxy(state) // true
isProxy(readonly(state)) // true
isProxy(count) // false
Copy the code
isReactive
Check whether the object is the corresponding mobile agent created by reactive
But if the proxy was created by readonly but wrapped around another proxy created by reactive, it will also return true
const state = reactive({ count : 0 })
isReactive(state) // true
isReactive(readonly(state)) // true
Copy the code
isReadOnly
Check whether the object is a read-only agent created by readonly
toRaw
Return the original object of the reactive or readonly proxy. (Use it with caution because persistent references to the original object are not recommended.)
shallowReactive
Shallow (shallow)
Create a responsive proxy that tracks the responsiveness of its own property, but does not perform deep responsive transformations of nested objects (deep versus native)
Similar to shallow copy, only the first layer is made responsive, and the deep layer is still the original object
shallowReadonly
Create a proxy that makes its own property read-only, but does not perform deep read-only transformations of nested objects
That means the first layer is read-only, but the deeper layer is still readable and writable
toRefs
Since we use ES6’s destructive syntax to destruct and assign values to objects returned by reactive, the destructed data is not responsive
And using toRefs, we can convert all the properties in the object that we return from reative to ref so that all the data that we deconstruct again is ref.
const state = reactive({ name:'wangpf' , age:18 });
const { name, age } = state; // The data is unresponsive
const { name, age } = toRefs(state) // This deconstructed data is converted to ref, which is responsive
// This creates a connection between state.name and name.value. Modifying either will cause the other to change
Copy the code
toRef
If we want to convert the properties of a reactive object toRef, we can use the toRef method
const state = reactive({ name:'wangpf' , age:18 });
const name = toRef(state,"name"); // The name is ref,
// Similarly, a connection is established between name.value and state.name, and the changes will affect each other
Copy the code
Ref other apis
unref
If you want to get the value in a ref reference, you can use the unref method:
-
If the parameter is a ref, return the internal value, otherwise return the parameter value
-
It’s actually a grammatical sugar:
-
val = isRef(val) ? val.value : val Copy the code
-
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // unwrapped must be numeric now
}
Copy the code
isRef
Determines if the value is a ref object
shallowRef
Create a shallow ref object
const info = shallowRef({ name: "wangpf" })
const changeInfo = () = > {
info.value.name = 'wpf' // The modification is not responsive
}
Copy the code
triggerRef
Manually triggers side effects associated with shallowRef
const info = shallowRef({ name: "wangpf" })
const changeInfo = () = > {
info.value.name = 'wpf' // The modification is not responsive
TriggerRef = triggerRef
triggerRef(info)
}
Copy the code
customRef
Create a custom REF and display control over its dependency tracking and update triggers
- It requires a factory function that takes the track and trigger functions as parameters
- It should return an object with get and set
An example of stabilization with customRef
import { customRef } from "vue";
export default function (value, delay = 300) {
let timer = null;
return customRef((track, trigger) = > {
return {
get() {
track();
return value;
},
set(newValue) {
clearTimeout(timer);
timer = setTimeout(() = >{ value = newValue; trigger(); }, delay); }}; }); }Copy the code
<template> <input type="text" v-model="message" /> <p>{{ message }}</p> </template> <script> import useDebounceRef from ".. /hooks/useDebounceRef"; export default { name: "Demo2", setup() { const message = useDebounceRef("hello", 300); return { message, }; }}; </script>Copy the code
computed
The API’s method is the same as vuE2’s, except that it is written in the setup function, but note that the value returned for computed is a ref
- Method one: receive a getter function and return the value for the getter, returning an invariant ref object
const firstName = ref("wangpf");
const lastName = ref("ok");
const fullName = computed(() = > `${firstName.value} ${lastName.value}`)
Copy the code
- Mode two: receive an object with get and set and return a variable (read and write) REF object
const firstName = ref("wangpf");
const lastName = ref("ok");
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`;
},
set(newValue) {
const names = newValue.split("");
firstName.value = names[0];
lastName.value = names[1]; }});const changeName = () = > {
fullName.value = "wpf err";
console.log(fullName.value);
};
Copy the code
Listen for data changes (Watch watchEffect)
In the Composition API, we can use watchEffect and Watch to do responsive data listening
- Watch needs to manually specify the data source to listen to
- WatchEffect is used to automatically collect dependencies for responsive data
watchEffect
Responsive to calculate and listen | Vue. Js (vuejs.org)
WatchEffect is used when we listen for some responsive data change and want to do something
Here’s a case:
const name = ref('wangpf')
const age = ref(18)
watchEffect(() = > {
console.log('watchEffect executed ',name.value,age.value)
})
Copy the code
- With the above code, the first function passed in watchEffect is executed immediately, and dependencies are collected during execution
- (The reason why you need to do it now is to collect dependencies.)
- Second, the function passed in by watchEffect is executed only if the collected dependencies change
WatchEffect stop listening
- If, at some point, we want to stop listening, we can get the watchEffect return value function and call it
Here’s an example:
const stopWatch = watchEffect(() = > {
console.log('watchEffect executed ',name.value,age.value)
})
const changeAge = () = > {
age.value++;
if(age.value > 20){
stopWatch() // To stop listening, discard the watchEffect return value}}Copy the code
WatchEffect Removes side effects
Use: for example, in development, we need to perform a network request in the listener function, but we stopped the listener before the network request arrived, or the listener function has been executed again, and we need to cancel the last network request
Here’s an example:
watchEffect((onInvalidate) = > {
console.log('watchEffect executed ',name.value,age.value)
const timer = setTimeout(() = > {
console.log('Operations performed after 1s')},1000)
onInvalidate(() = > {
// Do some cleanup here
clearTimeour(timer)
})
})
Copy the code
In the code above, the function we passed in to watchEffect is called back with one parameter: onInvalidate (which is a function), in which we can perform some cleanup.
WatchEffect execution time (refresh time)
By default, component updates are performed before the watchEffect (side effect function)
const title = ref(null); // The title is bound to the div tag
watchEffect(() = > {
console.log(title.value);
});
return { title };
Copy the code
So, when we get the element in watchEffect, the first execution is definitely null, it’s not allowed. Only after the DOM is mounted will the title be assigned a new value, and the watchEffect is executed again to print out the corresponding element
If we want to print the element the first time, we need to pass a second argument to watchEffect, which is an object with three values flush: ‘pre’ (default), ‘POST’, and ‘async’ (not recommended)
// Triggers after the component is updated, so you can access the updated DOM.
// Note: This will also delay the initial run of the side effects until the first rendering of the component is complete.
watchEffect(
() = > {
/ *... * /
},
{
flush: 'post' // Execute immediately after the DOM element is mounted or updated. "pre" executes immediately (default)})Copy the code
watch
The Watch API works the same way as watch in vUE 2’s Option API. By default, Watch only calls back when the listened source sends a change
Compared with watchEffect, the differences are:
- Watch is a side effect of lazy execution
- More specifically, what state should trigger a listener to restart
- The values before and after the state change can be accessed
Listening to a single data source
There are two ways to listen to a single data source: pass in a getter function or a ref object
/ / listen for the getter
const state = reactive({ name : 'wangpf' })
watch(() = > state.name , (newVal,oldVal) = > {
/ *... * /
})
/ / listen for ref
const name = ref('wamgpf')
watch(name,(newVal,oldVal) = > {
/ *... * /
// Where newVal,oldVal are the values of the returned ref.value
})
Copy the code
Listening to multiple data sources
Method: Pass in an array
const firstName = ref("AAA");
const lastName = ref("bbb");
const changeName = () = > {
firstName.value = "A";
lastName.value = "b";
};
watch([firstName, lastName], (newVal, oldVal) = > {
console.log("newVal:", newVal, "oldVal:", oldVal);
});
// newVal: ["A", "b"] oldVal: ["AAA", "bbb"]
Copy the code
Listen for responsive objects
Listen to reactive objects
const numbers = reactive([1.2.3.4])
watch(
() = > [...numbers],
(numbers, prevNumbers) = > {
console.log(numbers, prevNumbers)
}
)
numbers.push(5) / / logs: [1, 2, 3, 4, 5] [1, 2, 3, 4]
Copy the code
If you want to listen deeply on nested objects or arrays, you need to set deep to true,
const state = reactive({
id: 1.attributes: {
name: ' ',
}
})
watch(
() = > state,
(state, prevState) = > {
console.log(
'not deep',
state.attributes.name,
prevState.attributes.name
)
}
)
watch(
() = > state,
(state, prevState) = > {
console.log(
'deep',
state.attributes.name,
prevState.attributes.name
)
},
{ deep: true }
)
state.attributes.name = 'Alex' // Log: "deep" "Alex" "Alex"
Copy the code
But you’ll find that the new value is the same as the old one. This is where deep copy is needed for full listening
Other apis
Life cycle function
em…. Go look at the documentation,
Life cycle hook | Vue. Js (vuejs.org)
Provide / Inject
The function is the same as before,
We can provide data with provide
- Each property is defined through the provide method
- Pass two arguments: name (the supplied property name) and value (the supplied property value)
We can use JNject to inject what we want
- The name of the property to be injected
- Default value (Optional)
let count = ref(100)
let info = { name : "wangpf" , age : 18 }
provide("count",readonly(count))
provide("info",readonly(info)) // It is recommended to use readonly to wrap the value so that the data passed will not be changed by the inject component
// Obtain it from the descendant component via inject
const count = inject("count")
const info = inject("info")
Copy the code
H function
Before generating the real DOM, VUE will convert our nodes into vnodes, and the vnodes will form a tree structure, namely the virtual DOM
The HTML in the Template is the corresponding VNode generated using the render function
If we wanted to write the createVNode function in JavaScript to generate the corresponding VNode, we would use the h() function
The h() function is a common VNode function. The more accurate name is the createVNode() function, but vue has simplified it to h() for simplicity
The h() function takes three arguments: (tag, attribute, offspring)
h(
// {String | Object | Function} tag
// An HTML tag name, a component, an asynchronous component, or
// A functional component.
//
// Necessary.
'div'.// {Object} props
// The object corresponding to attribute, prop, and event.
// We will use it in the template.
//
// Optional.
{},
// {String | Array | Object} children
// Subvnodes, built with 'h()',
// Or get a "text Vnode" or using a string
// Objects with slots.
//
// Optional.
[
'Some text comes first.',
h('h1'.'A headline'),
h(MyComponent, {
someProp: 'foobar'})])Copy the code
Note: If there are no props, we can pass children as the second argument, but that would be ambiguous, so we would normally pass null as the second argument and children as the third
Basic use of the h function
- This can be used in the Render function option
- Can be used in the Setup function option
export default {
render(){
return h('div', { class:'app' }, 'hello app')}}export default {
setup(){
return () = > h('div', { class:'app' }, 'hello app')}}Copy the code
JSX is recommended. It has the same syntax as React, so I won’t go into details here. To see the document
jsx | Vue.js (vuejs.org)
Custom instruction
The custom command | Vue. Js (vuejs.org)
In Vue, the main form of code reuse and abstraction is components. However, in cases where you still need low-level manipulation of normal DOM elements, custom directives are used.
There are two types of custom instructions:
- Custom local directives: Using the Directives option in a component can only be used in the current component.
- Custom global directives: The app directive method can be used in any component.
The life cycle of the instruction
An object defined by a directive, Vue provides the following hook functions:
- Created: called before the attribute or event listener of the bound element is applied;
- BeforeMount: called when a directive is first bound to an element and before the parent component is mounted;
- Mounted: called after the parent component of the bound element is mounted.
- BeforeUpdate: called before updating the VNode containing components;
- Updated: called after the VNode that contains the component and its child components have been updated;
- BeforeUnmount: called before the parent component of the bound element is unmounted;
- Unmounted: called only once when the directive is unbound from the element and the parent component has been unmounted
These hook functions take four arguments: el, binding, vnode, and prevNnode
Example: time formatting instruction
Teleport
Teleport | Vue.js (vuejs.org)
Teleporting components that can be moved to other DOM elements.
Usually used to encapsulate modal boxes, toast, etc., place it on the Body element at the level of the div#app element
The two properties
- To: Specifies the target element to which to move its contents, using a selector
- Disabled: Indicates whether to disable the teleport function
<teleport :to='#demo'>
<h2>hello</h2>
</teleport>
// The element will be transferred to the element with id demo
Copy the code
Vue plug-in
Plugins | Vue. Js (vuejs.org)
Typically, we use the plug-in pattern when adding functionality to Vue globally
Two ways to write it
- Object type
- aobject, but must include one
install
The function,This function is executed when the plug-in is installed
- aobject, but must include one
- Function types
- A function that is automatically executed when the plug-in is installed
// plugin_obect.js
export default {
install(app) {
app.config.globalProperties.$name = "wangpf"; }};// main.js
import plugin_object from "./plugins/plugin_object";
app.use(plugin_object);
// app.vue
import { getCurrentInstance } from "vue";
setup() {
const Instance = getCurrentInstance();
console.log("Instance", Instance.appContext.config.globalProperties.$name);
}
Copy the code