I have been writing articles related to Vue recently. If you are interested, please refer back to my previous articles.
A collection of author’s articles
- “Learn from source” thoroughly understand the Vue option Props
- The “Vue Practice” project upgrades vuE-CLI3 to correct posture
- “Learn from the source” Vue source JS operations
- Why do you never understand JavaScript scope chains?
Eat this fish 🐟 –props
Initialize the
initProps
How it works:
1.normalizeProps
: initProps
Previously normalized data
The code for normalizeProps is a bit long, so this is just a list of normalized prop types and results
1.1 the string
Props: ["data"] // Props :{data:{type: null}}Copy the code
1.2 object
// Props: {data1: {type: String, default: "} data2: Number,} // Props: {data1: {type: String, default: "} '' }, data2: { type: Number }, }Copy the code
2.initProps
: handlingprops
Source code analysis is as follows:
function initProps (vm: Component, propsOptions: Object) { const propsData = vm.$options.propsData || {} const props = vm._props = {} const keys = vm.$options._propKeys = [] const isRoot = ! vm.$parent if (! isRoot) { toggleObserving(false) } for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) if (process.env.NODE_ENV ! == 'production') { const hyphenatedKey = hyphenate(key) if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { if (! isRoot && ! isUpdatingChildComponent) { warn( `Avoid mutating a prop direct.... `, vm ) } }) } else { defineReactive(props, key, value) } if (! (key in vm)) { proxy(vm, `_props`, key) } } toggleObserving(true) }Copy the code
2.1 Constant Definition
const propsData = vm.$options.propsData || {} const props = vm._props = {} const keys = vm.$options._propKeys = [] const isRoot = ! vm.$parentCopy the code
propsData
: stores what is passed inprops
The value of theProps: reference
Vm._props’, and initialized to {}keys
In:vm.$options
To add_propKeys
attributeisRoot
: Checks whether it existsvm.$parent
If no, it is the root node
2.2 Condition judgment and circulation
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
// 省略...
}
toggleObserving(true)
Copy the code
! isRoot
: If the current instance is not the root node, close ittoggleObserving
toggleObserving
: can be understood as the switch of data observationfor... in
: traversalpropsOptions
2.2.1: traversalpropsOptions
What do you do
for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) if (process.env.NODE_ENV ! == 'production') { const hyphenatedKey = hyphenate(key) if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { if (! isRoot && ! isUpdatingChildComponent) { warn( `Avoid mutating a prop directly since the value will be ` + `overwri tten whenever the parent component re-renders. ` + `Instead, use a data or computed property based on the prop's ` + `value. Prop being mutated: "${key}"`, vm ) } }) } else { defineReactive(props, key, value) } }Copy the code
To highlight:
propsOptions
即opts.props
key
Is that eachprop
The name of the
Enter the loop:
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
Copy the code
- will
key
Added to thevm.$options._propKeys
value
:validateProp
Verify that it is the expected type value and return the corresponding prop value (or default value)
2.2.2: Then enterif... else
:
Here’s a note:
if (process.env.NODE_ENV ! == 'production') {const hyphenatedKey = hyphenate(key); key,ref,slot,slot-scope,is if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, Value, () => {// warning if (! isRoot && ! isUpdatingChildComponent) { warn( `Avoid mutating a prop directly since the value will be ` + `overwri tten whenever the parent component re-renders. ` + `Instead, use a data or computed property based on the prop's ` + `value. Prop being mutated: "${key}"`, vm ) } }) } else { defineReactive(props, key, value) }Copy the code
Finally simplify:
if (process.env.NODE_ENV ! == 'production') {// prop is a built-in property // built-in property: Key,ref,slot,slot-scope,is DefineReactive (props, key, value, () => {} else {defineReactive(props, key, value)}Copy the code
Tool function: “learn from the source” Vue source JS operations
2.2.3: defineReactive
: Final processing
defineReactive(props, key, value)
Copy the code
DefineReactive is an old acquaintance, but one thing to note here: toggleObserving(false) turns off the observing switch, so the observe call in defineReactive is an invalid call.
Now, at this point, we can draw a conclusion
Props is defined by defineReactive, which is reactive data but not deeply defined.
That is, after the parent component passes to the child component props, the child component does not have to observe againprops
2.2.4 toggleObserving(true) : Finally, turn on the observing switch
toggleObserving(true)
Copy the code
Turn on the observation switch again to avoid affecting the subsequent code execution.