Modular API
01-setup
- We know it’s new in Vue3.0
setup
Instead of abeforeCreate
和created
And,setup
比beforeCreate
和created
Perform more early
export default {
beforeCreate () {
console.log('beforeCreate')
},
created () {
console.log('created')},setup() {
console.log('setup')}}Copy the code
-
The setup function is the entry point to the Composition API, where all Composition API functions are used and executed only once during initialization
-
Properties and methods defined in the setup function must eventually be returned or they cannot be used in the template
-
The official setup template example
<template>
<div>{{ readersNumber }} {{ book.title }}</div>
</template>
Copy the code
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// expose to template
return {
readersNumber,
book
}
}
}
</script>
Copy the code
parameter
The setup function takes two parameters, props and context
props
The props in the setup function is reactive and will be updated when the parent passes in a new props
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
Copy the code
Note: Because props are reactive, you cannot use ES6 deconstruction, which would eliminate the responsiveness of prop
Context
Context is a plain JavaScript object that exposes the component’s three properties
export default {
setup(props, context) {
// Attribute (non-responsive object)
console.log(context.attrs)
// slot (non-responsive object)
console.log(context.slots)
// Trigger event (method)
console.log (context) emit)}} orexport default {
setup(props, { attrs, slots, emit }){... }}Copy the code
Attrs and slots are stateful objects that are always updated as the component itself is updated. This means you should avoid deconstructing them and always refer to properties as attrs.x or slots.x
Access the component’s property
When SETUP is executed, the component instance has not yet been created. Therefore, you can only access the following property:
- props
- attrs
- slots
- emit
this
Calling this in setup is undefined because setup() is called before parsing other component options, so this inside setup() behaves completely differently than this in other options.
02- Life cycle
Vue3.0 calls the lifecycle hook inside setup ()
Vue2.x | Vue3.x |
---|---|
beforeCreate | No longer need |
created | No longer need |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
New hook function
- onRenderTracked
- onRenderTriggered
If you continue to use the Vue2. X syntax
- BeforeUnmount replaces beforeDestroy
- Unmounted replaces destroyed
03-ref
-
Function: Defines a response to data
-
Syntax: const XXX = ref(initValue);
-
To access and modify the count variable inside setup, use count.value
-
To manipulate data in a template:.value is not required
-
The sample
<template>
{{count}}
</template>
Copy the code
setup {
const count = ref(0)
console.log(count.value) / / 0
count.value++
console.log(count.value) / / 1
return {count}
}
Copy the code
- Ref recommends defining basic data types, but you can also use complex data types, because if you define objects or arrays in ref, the Vue will help you convert them to
Reactive object
7. Implement ref by hand
// define a ref
function ref (target) {
// Reactive is implemented when the object type is specified
target = reactive(target)
return {
_is_ref: true.// Identifies the current object as a ref object
// Save the target data
_value: target,
get value () {
console.log('Hijacked to read data')
return this._value;
},
set value (val) {
console.log('Hijacked modify data, ready to update interface', val)
this._value = val; }}}Copy the code
ref
Get elements, for example, get input focus/call a function of a child component or access its properties
<template>
<h2>App</h2>
<input type="text">---
<input type="text" ref="inputRef">
<button @click="open">Open the popup window</button>
<update ref="updateRef" />
</template>
Copy the code
<script lang="ts">
import { onMounted, ref } from 'vue'
import Update from "./components/update.vue"
export default {
components: {
Update
},
setup() {
/** * Automatically get input focus */
const inputRef = ref<HTMLElement|null> (null)
onMounted(() = > {
inputRef.value && inputRef.value.focus()
})
/** * Automatically calls the child component's open function */
const updateRef = ref(null);
const open = () = > { updateRef.value.open(); };
return {
inputRef
}
},
}
</script>
Copy the code
04-unref
- If the argument is one
ref
, returns the internal value, otherwise returns the parameter itself. - This is val = isRef(val), right? Val. value: The syntactic sugar function of val.
- Handwritten implementation
unref
// define a function unref to determine whether the current object is a ref object
function unref (target) {
return target && target._is_ref? target.value : target;
}
Copy the code
05-toRef
-
Can be used to create a new REF for a property on a source responsive object. The REF can then be passed, maintaining a reactive connection to its source property
-
Ref = ref
ref
A copy of a new data value is operated separately, without affecting each other during updatetoRef
It maintains a reactive connection to its source property
-
Example 1: Reactive connection
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
- Example 2 If: defined
hook
The function needs a ref object
// Only one ref object is received, and the value of ref is returned
function useData(foo: Ref) {
return foo.value;
}
const component = defineComponent({
props: {
foo: {
type: Number.require: true
}
},
setup (props, context) {
const data = useData(toRef(props, 'foo'))
return {
data
}
}
})
Copy the code
- ToRef is implemented by handwriting
// Define a function toRef that can be used to create a new ref for a property on a source responsive object. The REF can then be passed, maintaining a reactive connection to its source property.
function toRef(target, prop) {
let _target = target[prop];
let state = target && target._is_reactive;
return {
_value: _target,
get value() {
this._value = state ? target[prop] : this._value;
return this._value;
},
set value(val) {
this._value = val; target[prop] = state ? val : target[prop]; }}; }Copy the code
06-toRefs
- Converts a reactive object to a normal object, where each of the result objects
property
They all point to the original objectproperty
的ref
. - When a responsive object is returned from a combined function,
toRefs
Very useful so that the consuming component can decompose/diffuse the returned object without losing responsiveness: toRefs
Will only be contained in the source objectproperty
generateref
. Use this if you want to create a REF for a particular propertytoRef
- The sample
setup {
const data = reactive({
tableData: [].loading: false,})// In the template we want to use the tableData and loading properties directly,
// "..." It becomes unresponsive,
// Destruct without losing responsiveness
return {
...toRefs(data),
}
}
Copy the code
- Handwritten implementation
toRefs
// Define a toRefsHandler handler object
function toRefsHandler(prop, val) {
return {
_value: val,
__v_isRef: true._key: String(prop),
get value() {
return this._value;
},
set value(val) {
this._value = val; }}; }// Define a function toRefs that converts a reactive object to a normal object, where each property of the resulting object is a ref to the corresponding property of the original object.
function toRefs(target) {
let result = {};
if (target && typeof target '= "object") {if (array.isarray (target)) {// Array data to traverse target.foreach ((item, index) => { result[index] = toRefsHandler(index, item); }); ForEach ((key) => {result[key] = toRefsHandler(key, target[key]); }); } return result; }}Copy the code
07-isRef
- Check if the value is a ref object
- Handwritten implementation
isRef
function isRef(obj) {
return obj && obj._is_ref
}
Copy the code
08-shallowRef
- Create a trace itself
.value
Changes the ref, but does not make its value also responsive - Shallow hijacking (shallow monitoring)—- shallow response
- Handwritten implementation
shallowRef
function shallowRef(target) {
const result = {
_value: target, // An internal attribute used to hold data
_is_ref: true.// is used to identify the ref object
get value () {
return this._value
},
set value (val) {
this._value = val
console.log('Set value data has been updated, go update interface')}}return result
}
Copy the code
09-customRef
- Create a custom
ref
And has explicit control over its dependency tracing and update triggering. - It requires a factory function that accepts
track
和trigger
Function as arguments, and should return an object with get and set - Using custom
ref
throughv-model
implementationdebounce
Example:
<input v-model="text" />
Copy the code
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) = > {
return {
get() {
// Trace its dependencies
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() = > {
value = newValue
// Update triggered
trigger()
}, delay)
}
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello')}}}Copy the code
10-triggerRef
- Manual execution and
shallowRef
Associated with any side effects.
const shallow = shallowRef({
greet: 'Hello, world'
})
// Record "Hello, world" on the first run
watchEffect(() = > {
console.log(shallow.value.greet)
})
// This does not trigger side effects because refs are shallow
shallow.value.greet = 'Hello, universe'
// record "Hello, universe"
triggerRef(shallow)
Copy the code
11-reactive
- Returns a reactive copy of the object
- Deep hijacking (deep monitoring)—- deep responsiveness
- Reactive transformation is “deep” — it affects all nested properties
- Through internal
Proxy
和Reflect
implementation - Handwritten implementation
reactive
// Define a reactiveHandler handler object
const reactiveHandler = {
// Get the attribute value
get(target, prop) {
if (prop `= "_is_reactive") return true; const result = Reflect.get(target, prop); Console. log(" intercepted read data ", prop, result); return result; }, // Add attribute set(target, prop, value) {const result = reflect. set(target, prop, value); Console. log(" intercepted modified data or added properties ", prop, value); return result; }, // Delete a property deleteProperty(target, prop) {const result = reflect.deleteProperty (target, prop); Console. log(" blocked deleted data ", prop); return result; }}; Function reactive(target) {if (target && typeof target ') {function reactive(target) {if (target && typeof target '= "object") {
// Perform recursive processing of all data in arrays or objects reactive
// Check whether the current data is an array
if (Array.isArray(target)) {
// The array is traversed
target.forEach((item, index) = > {
target[index] = reactive(item);
});
} else {
// Determine if the current data is an object
// The data of the object is also traversed
Object.keys(target).forEach((key) = > {
target[key] = reactive(target[key]);
});
}
return new Proxy(target, reactiveHandler);
}
// If the data passed in is of a primitive type, it is returned directly
return target;
}
Copy the code
12-readonly
- A read-only proxy that accepts an object (reactive or pure) or ref and returns the original object
- A read-only proxy is deep: any nested property accessed is also read-only.
- with
reactive
Same if any property is usedref
When accessed through a proxy, it is automatically unpacked:
const raw = {
count: ref(123)}const copy = readonly(raw)
console.log(raw.count.value) / / 123
console.log(copy.count) / / 123
Copy the code
- Handwritten implementation
readonly
// Defines a readonlyHandler handler
const readonlyHandler = {
get(target, prop) {
if (prop `= "_is_readonly") return true; const result = Reflect.get(target, prop); Console. log(" read data intercepted ", prop, result); return result; }, set(target, prop, value) {console.warn(" can only read data, cannot modify data or add data "); return true; }, deleteProperty(target, prop) {console.warn(" read data only, don't delete data "); return true; }}; Function readonly(target) {if (target && typeof target '= "object") {
// Check whether target is an array
if (Array.isArray(target)) {
// go through the number group
target.forEach((item, index) = > {
target[index] = readonly(item);
});
} else {
// Determine whether target is an object
// Iterate over the object
Object.keys(target).forEach((key) = > {
target[key] = readonly(target[key]);
});
}
return new Proxy(target, readonlyHandler);
}
// If it is not an object or array, return it directly
return target;
}
Copy the code
13-isProxy
- Check whether the object is created by
reactive
或readonly
Create the proxy - The return value is Boolean
- Handwritten implementation
isProxy
// Define a function isProxy to check whether the current object is reactive or readonly
function isProxy(obj) {
return isReactive(obj) || isReadonly(obj);
}
Copy the code
14-isReactive
- Check whether the object is created by
reactive
Create a responsive proxy. - The return value is of Boolean type
- Handwritten implementation
isReactive
// Define a function isReactive to check whether the current object is a reactive object
function isReactive(obj) {
return obj && obj._is_reactive;
}
Copy the code
15-isReadonly
- Check whether the object is a read-only proxy created by ReadOnly
- The return value is of Boolean type
- Handwritten implementation
isReadonly
// Define a function isReadonly to determine whether the current object is a readOnly object
function isReadonly(obj) {
return obj && obj._is_readonly;
}
Copy the code
15-toRaw
- return
reactive
或readonly
The original object of the proxy. - Changed the proxy object into a normal object, the data changes, the interface does not change
- It is not officially recommended.
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) `= foo) // true
Copy the code
16-markRaw
- Marks an object so that it will never be converted to a proxy. Return the object itself
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// Can also be used when nested within other reactive objects
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
Copy the code
17-shallowReactive
- Create a reactive proxy that tracks the responsiveness of its own property, but does not perform deep reactive transformations of nested objects (exposing raw values).
- Shallow hijacking (shallow monitoring)—- shallow response
- The official sample
const state = shallowReactive({
foo: 1.nested: {
bar: 2}})// Changing the nature of state itself is reactive
state.foo++
/ /... But nested objects are not converted
isReactive(state.nested) // false
state.nested.bar++ // non-responsive
Copy the code
- Handwritten implementation
shallowReactive
// Define a shallowReactive function that passes in a target object
function shallowReactive(target) {
// Check whether the current target object is of type object (object/array)
if (target && typeof target `= "object") { return new Proxy(target, reactiveHandler); } // If the data passed is of a primitive type, return target directly; }Copy the code
18-shallowReadonly
- Create a proxy that makes its own property read-only, but does not perform deep read-only conversion of nested objects (exposing raw values)
- Shallow hijacking (shallow monitoring)—- shallow read-only
- The official sample
onst state = shallowReadonly({
foo: 1.nested: {
bar: 2}})// Changing the property of state itself will fail
state.foo++
/ /... But it applies to nested objects
isReadonly(state.nested) // false
state.nested.bar++ / / for
Copy the code
- Handwritten implementation
shallowReadonly
// Define a shallowReadonly function
function shallowReadonly(target) {
// We need to determine whether the current data is an object
if (target && typeof target `= "object") { return new Proxy(target, readonlyHandler); } return target; }Copy the code
19 – dojo.provide and inject
- Provide and inject provide dependency injection functions similar to those of 2.x
provide/inject
- Realize communication between components (grandparent and grandchild) across hierarchies
<! -- Parent component -->
<template>
<h2>The parent component</h2>
<Son />
</template>
<script lang="ts">
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'ProvideInject'.components: {
Son
},
setup() {
const msg = ref('I'm the MSG of the parent component')
provide('msg', msg)
return {
msg
}
}
}
</script>
Copy the code
<! Son.vue--> <template> <div> <h2> <hr> <GrandSon /> </div> </template> <script lang="ts"> import GrandSon from './GrandSon.vue' export default { components: { GrandSon }, } </script>Copy the code
<! <template> <h3 :style="{MSG}"> {{msg}}</h3> </template> <script lang="ts"> import { inject } from 'vue' export default { setup() { const msg = inject('msg') return { msg } } } </script>Copy the code
At the end
- This article is mainly for the author to learn Vue3.0 from teacher Yang Hongbo
- This article incorporates the official Vue3.0 documentation
- The handwritten part of this article is only a simple implementation, which has not considered the complex logic
- If there is any improper please correct