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 🐟 –propsInitialize the

initPropsHow it works:

1.normalizeProps: initPropsPreviously 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 inpropsThe value of the
  • Props: referenceVm._props’, and initialized to {}
  • keysIn:vm.$optionsTo add_propKeysattribute
  • isRoot: Checks whether it existsvm.$parentIf 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 observation
  • for... in: traversalpropsOptions

2.2.1: traversalpropsOptionsWhat 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:

  • propsOptionsopts.props
  • keyIs that eachpropThe name of the

Enter the loop:

keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
Copy the code
  • willkeyAdded to thevm.$options._propKeys
  • value:validatePropVerify 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.

Insight: It’s harder to blog after understanding than analyzing source code. Saying something clearly in words is much harder than typing code.