Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
vue3.0 ÏìӦʽԭÀí(³¬Ïêϸ)
 
 
  2114  次浏览      27
 2021-3-3
 
±à¼­ÍƼö:
±¾ÎÄÖ÷Òª½éÉÜÁËvue3.0 ÈçºÎ½¨Á¢ÏìӦʽ,ÏìӦʽԭÀí,À¹½ØÆ÷¶ÔÏóbaseHandlersÒÔ¼°×é¼þ³õʼ»¯½×¶Î£¬Ï£Íû¶ÔÄúµÄѧϰÓÐËù°ïÖú¡£
±¾ÎÄÀ´×ÔÓÚ΢ÐŹ«ÖÚºÅ,ÓÉ»ðÁú¹ûÈí¼þAlice±à¼­ÍƼö¡£

Ò» »ùÓÚproxyµÄObserver

1 ʲôÊÇproxy

Proxy ¶ÔÏóÓÃÓÚ¶¨Òå»ù±¾²Ù×÷µÄ×Ô¶¨ÒåÐÐΪ£¨ÈçÊôÐÔ²éÕÒ¡¢¸³Öµ¡¢Ã¶¾Ù¡¢º¯Êýµ÷Óõȣ©¡£

proxyÊÇes6ÐÂÌØÐÔ£¬ÎªÁ˶ÔÄ¿±êµÄ×÷ÓÃÖ÷ÒªÊÇͨ¹ýhandler¶ÔÏóÖеÄÀ¹½Ø·½·¨À¹½ØÄ¿±ê¶ÔÏótargetµÄijЩÐÐΪ£¨ÈçÊôÐÔ²éÕÒ¡¢¸³Öµ¡¢Ã¶¾Ù¡¢º¯Êýµ÷Óõȣ©¡£

/* target: Ä¿±ê¶ÔÏ󣬴ýҪʹÓà Proxy °ü×°µÄÄ¿±ê¶ÔÏó £¨¿ÉÒÔÊÇÈκÎÀàÐ͵ĶÔÏ󣬰üÀ¨Ô­ÉúÊý×飬º¯Êý£¬ÉõÖÁÁíÒ»¸ö´úÀí£©¡£ */
/* handler: Ò»¸öͨ³£ÒÔº¯Êý×÷ΪÊôÐԵĶÔÏó£¬ ¸÷ÊôÐÔÖеĺ¯Êý·Ö±ð¶¨ÒåÁËÔÚÖ´Ðи÷ÖÖ²Ù×÷ʱ´úÀí proxy µÄÐÐΪ¡£ */
const proxy = new Proxy(target, handler);

2 ΪʲôҪÓÃproxy£¬¸ÄÓÃproxyÖ®ºóµÄÀûÓë±×

> 3.0 ½«´øÀ´Ò»¸ö»ùÓÚ Proxy µÄ observer ʵÏÖ£¬Ëü¿ÉÒÔÌṩ¸²¸ÇÓïÑÔ (JavaScript¡ª¡ªÒë×¢) È«·¶Î§µÄÏìӦʽÄÜÁ¦£¬Ïû³ýÁ˵±Ç° Vue 2 ϵÁÐÖлùÓÚ Object.defineProperty Ëù´æÔÚµÄһЩ¾ÖÏÞ£¬ÕâЩ¾ÖÏÞ°üÀ¨£º1 ¶ÔÊôÐÔµÄÌí¼Ó¡¢É¾³ý¶¯×÷µÄ¼à²â£» 2 ¶ÔÊý×é»ùÓÚϱêµÄÐ޸ġ¢¶ÔÓÚ .length Ð޸ĵļà²â£» 3 ¶Ô Map¡¢Set¡¢WeakMap ºÍ WeakSet µÄÖ§³Ö£»£»

vue2.0 ÓÃObject.defineProperty ×÷ΪÏìӦʽԭÀíµÄʵÏÖ£¬µ«ÊÇ»áÓÐËüµÄ¾ÖÏÞÐÔ£¬±ÈÈç ÎÞ·¨¼àÌýÊý×é»ùÓÚϱêµÄÐ޸쬲»Ö§³Ö Map¡¢Set¡¢WeakMap ºÍ WeakSetµÈȱÏÝ £¬ËùÒÔ¸ÄÓÃÁËproxy½â¾öÁËÕâЩÎÊÌ⣬ÕâÒ²Òâζ×Åvue3.0½«·ÅÆú¶ÔµÍ°æ±¾ä¯ÀÀÆ÷µÄ¼æÈÝ£¨¼æÈݰ汾ie11ÒÔÉÏ£©¡£

3 proxyÖÐhander¶ÔÏóµÄ»ù±¾Ó÷¨

vue3.0 ÏìӦʽÓõ½µÄ²¶»ñÆ÷£¨½ÓÏÂÀ´»áÖØµã½éÉÜ£©

handler.has() -> in ²Ù×÷·ûµÄ²¶×½Æ÷¡£ (vue3.0 Óõ½)

handler.get() -> ÊôÐÔ¶ÁÈ¡ ²Ù×÷µÄ²¶×½Æ÷¡£ (vue3.0 Óõ½)

handler.set() -> ÊôÐÔÉèÖà ²Ù×÷µÄ²¶×½Æ÷¡£(vue3.0 Óõ½)

handler.deleteProperty() -> delete ²Ù×÷·û µÄ²¶×½Æ÷(vue3.0 Óõ½)

handler.ownKeys() -> Object.getOwnPropertyNames ·½·¨ºÍ Object.getOwnPropertySymbols ·½·¨µÄ²¶×½Æ÷¡£(vue3.0 Óõ½)¡£

vue3.0 ÏìӦʽûÓõ½µÄ²¶»ñÆ÷£¨ÓÐÐËȤµÄͬѧ¿ÉÒÔÑо¿Ò»Ï£©

handler.getPrototypeOf() -> Object.getPrototypeOf ·½·¨µÄ²¶×½Æ÷¡£

handler.setPrototypeOf() -> Object.setPrototypeOf·½·¨µÄ²¶×½Æ÷¡£

handler.isExtensible() -> Object.isExtensible ·½·¨µÄ²¶×½Æ÷¡£

handler.preventExtensions() -> Object.preventExtensions ·½·¨µÄ²¶×½Æ÷¡£

handler.getOwnPropertyDescriptor()-> Object.getOwnPropertyDescriptor ·½·¨µÄ²¶×½Æ÷¡£

handler.defineProperty() -> Object.defineProperty·½·¨µÄ²¶×½Æ÷¡£

handler.apply() -> º¯Êýµ÷ÓòÙ×÷ µÄ²¶×½Æ÷¡£

handler.construct() -> new ²Ù×÷·û µÄ²¶×½Æ÷¡£

¢Ù has²¶»ñÆ÷

has(target, propKey)

target:Ä¿±ê¶ÔÏó

propKey:´ýÀ¹½ØÊôÐÔÃû

×÷ÓÃ: À¹½ØÅжÏtarget¶ÔÏóÊÇ·ñº¬ÓÐÊôÐÔpropKeyµÄ²Ù×÷

À¹½Ø²Ù×÷£ºpropKey in proxy ²»°üº¬for...inÑ­»·

¶ÔÓ¦Reflect: Reflect.has(target, propKey)

Àý×Ó£º

const handler = {
has(target, propKey){
/*
* ×öÄãµÄ²Ù×÷
*/
return propKey in target
}
}
const proxy = new Proxy(target, handler)

¢Ú get²¶»ñÆ÷

get(target, propKey, receiver)

target:Ä¿±ê¶ÔÏó

propKey:´ýÀ¹½ØÊôÐÔÃû

receiver: proxyʵÀý

·µ»Ø£º ·µ»Ø¶ÁÈ¡µÄÊôÐÔ

×÷ÓãºÀ¹½Ø¶ÔÏóÊôÐԵĶÁÈ¡

À¹½Ø²Ù×÷£ºproxy[propKey]»òÕßµãÔËËã·û

¶ÔÓ¦Reflect£º Reflect.get(target, propertyKey[, receiver])

Àý×Ó£º

const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 'ûÓдËË®¹û';
}
}

const foot = new Proxy({}, handler)
foot.apple = 'Æ»¹û'
foot.banana = 'Ïã½¶';

console.log(foot.apple, foot.banana); /* Æ»¹û Ïã½¶ */
console.log('pig' in foot, foot.pig); /* false ûÓдËË®¹û */

ÌØÊâÇé¿ö

const person = {};
Object.defineProperty(person, 'age', {
value: 18,
writable: false,
configurable: false
})
const proxPerson = new Proxy(person, {
get(target,propKey) {
return 20
//Ó¦¸Ãreturn 18;²»ÄÜ·µ»ØÆäËûÖµ£¬·ñÔò±¨´í
}
})
console.log( proxPerson.age ) /* »á±¨´í */

¢Û set²¶»ñÆ÷

set(target,propKey, value,receiver)

target:Ä¿±ê¶ÔÏó

propKey:´ýÀ¹½ØÊôÐÔÃû

value:ÐÂÉèÖõÄÊôÐÔÖµ

receiver: proxyʵÀý

·µ»Ø£ºÑϸñģʽÏ·µ»Øtrue²Ù×÷³É¹¦£»·ñÔòʧ°Ü£¬±¨´í

×÷Ó㺠À¹½Ø¶ÔÏóµÄÊôÐÔ¸³Öµ²Ù×÷

À¹½Ø²Ù×÷£º proxy[propkey] = value

¶ÔÓ¦Reflect£º Reflect.set(obj, prop, value, receiver)

let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) { /* Èç¹ûÄêÁä²»ÊÇÕûÊý */
throw new TypeError('The age is not an integer')
}
if (value > 200) { /* ³¬³öÕý³£µÄÄêÁ䷶Χ */
throw new RangeError('The age seems invalid')
}
}
obj[prop] = value
// ±íʾ³É¹¦
return true
}
}
let person = new Proxy({}, validator)
person.age = 100
console.log(person.age) // 100
person.age = 'young' // Å׳öÒì³£: Uncaught TypeError: The age is not an integer
person.age = 300 // Å׳öÒì³£: Uncaught RangeError: The age seems invalid````

µ±¶ÔÏóµÄÊôÐÔwritableΪfalseʱ£¬¸ÃÊôÐÔ²»ÄÜÔÚÀ¹½ØÆ÷Öб»ÐÞ¸Ä

const person = {};
Object.defineProperty(person, 'age', {
value: 18,
writable: false,
configurable: true,
});

const handler = {
set: function(obj, prop, value, receiver) {
return Reflect.set(...arguments);
},
};
const proxy = new Proxy(person, handler);
proxy.age = 20;
console.log(person) // {age: 18} ˵Ã÷ÐÞ¸Äʧ°Ü

¢Ü deleteProperty ²¶»ñÆ÷

deleteProperty(target, propKey)

target:Ä¿±ê¶ÔÏó

propKey:´ýÀ¹½ØÊôÐÔÃû

·µ»Ø£ºÑϸñģʽÏÂÖ»Óзµ»Øtrue, ·ñÔò±¨´í

×÷Ó㺠À¹½ØÉ¾³ýtarget¶ÔÏóµÄpropKeyÊôÐԵIJÙ×÷

À¹½Ø²Ù×÷£º delete proxy[propKey]

¶ÔÓ¦Reflect£º Reflect.delete(obj, prop)

var foot = { apple: 'Æ»¹û' , banana:'Ïã½¶' }
var proxy = new Proxy(foot, {
deleteProperty(target, prop) {
console.log('µ±Ç°É¾³ýË®¹û :',target[prop])
return delete target[prop]
}
});
delete proxy.apple
console.log(foot)

/*
ÔËÐнá¹û£º
'µ±Ç°É¾³ýË®¹û : Æ»¹û'
{ banana:'Ïã½¶' }

ÌØÊâÇé¿ö£º ÊôÐÔÊDz»¿ÉÅäÖÃÊôÐÔʱ£¬²»ÄÜɾ³ý

var foot = { apple: 'Æ»¹û' }
Object.defineProperty(foot, 'banana', {
value: 'Ïã½¶',
configurable: false
})
var proxy = new Proxy(foot, {
deleteProperty(target, prop) {
return delete target[prop];
}
})
delete proxy.banana /* ûÓÐЧ¹û */
console.log(foot)

¢ÝownKeys ²¶»ñÆ÷

ownKeys(target)

target£ºÄ¿±ê¶ÔÏó

·µ»Ø£º Êý×飨Êý×éÔªËØ±ØÐëÊÇ×Ö·û»òÕßSymbol,ÆäËûÀàÐͱ¨´í£©

×÷Ó㺠À¹½Ø»ñÈ¡¼üÖµµÄ²Ù×÷

À¹½Ø²Ù×÷£º

1 Object.getOwnPropertyNames(proxy)

2 Object.getOwnPropertySymbols(proxy)

3 Object.keys(proxy)

4 for...in...Ñ­»·

¶ÔÓ¦Reflect£ºReflect.ownKeys()

var obj = { a: 10, [Symbol.for('foo')]: 2 };
Object.defineProperty(obj, 'c', {
value: 3,
enumerable: false
})
var p = new Proxy(obj, {
ownKeys(target) {
return [...Reflect.ownKeys(target), 'b', Symbol.for('bar')]
}
})
const keys = Object.keys(p) // ['a']
// ×Ô¶¯¹ýÂ˵ôSymbol/·Ç×ÔÉí/²»¿É±éÀúµÄÊôÐÔ

/* ºÍObject.keys()¹ýÂËÐÔÖÊÒ»Ñù£¬Ö»·µ»Øtarget±¾ÉíµÄ¿É±éÀúÊôÐÔ */
for(let prop in p) {
console.log('prop-',prop) /* prop-a */
}

/* Ö»·µ»ØÀ¹½ØÆ÷·µ»ØµÄ·ÇSymbolµÄÊôÐÔ£¬²»¹ÜÊDz»ÊÇtargetÉϵÄÊôÐÔ */
const ownNames = Object.getOwnPropertyNames(p) /* ['a', 'c', 'b'] */

/* Ö»·µ»ØÀ¹½ØÆ÷·µ»ØµÄSymbolµÄÊôÐÔ£¬²»¹ÜÊDz»ÊÇtargetÉϵÄÊôÐÔ*/
const ownSymbols = Object.getOwnPropertySymbols(p)// [Symbol(foo), Symbol(bar)]

/*·µ»ØÀ¹½ØÆ÷·µ»ØµÄËùÓÐÖµ*/
const ownKeys = Reflect.ownKeys(p)
// ['a','c',Symbol(foo),'b',Symbol(bar)]

¶þ vue3.0 ÈçºÎ½¨Á¢ÏìӦʽ

vue3.0 ½¨Á¢ÏìӦʽµÄ·½·¨ÓÐÁ½ÖÖ£º

µÚÒ»¸ö¾ÍÊÇÔËÓÃcomposition-apiÖеÄreactiveÖ±½Ó¹¹½¨ÏìӦʽ£¬composition-apiµÄ³öÏÖÎÒÃÇ¿ÉÒÔÔÚ.vueÎļþÖУ¬Ö±½ÓÓÃsetup()º¯ÊýÀ´´¦Àí֮ǰµÄ´ó²¿·ÖÂß¼­£¬Ò²¾ÍÊÇ˵ÎÒÃÇûÓбØÒªÔÚ export default{ } ÖÐÔÚÉùÃ÷ÉúÃüÖÜÆÚ £¬ data(){} º¯Êý£¬watch{} , computed{} µÈ £¬È¡¶ø´úÖ®µÄÊÇÎÒÃÇÔÚsetupº¯ÊýÖУ¬ÓÃvue3.0 reactive watch ÉúÃüÖÜÆÚapiÀ´µ½´ïͬÑùµÄЧ¹û£¬ÕâÑù¾ÍÏñreact-hooksÒ»ÑùÌáÉý´úÂëµÄ¸´ÓÃÂÊ£¬Âß¼­ÐÔ¸üÇ¿¡£

µÚ¶þ¸ö¾ÍÊÇÓô«Í³µÄ data(){ return{} } ÐÎʽ ,vue3.0ûÓÐ·ÅÆú¶Ôvue2.0д·¨µÄÖ§³Ö£¬¶øÊǶÔvue2.0µÄд·¨ÊÇÍêÈ«¼æÈݵģ¬ÌṩÁËapplyOptions À´´¦ÀíoptionsÐÎʽµÄvue×é¼þ¡£µ«ÊÇoptionsÀïÃæµÄdata , watch , computedµÈ´¦ÀíÂß¼­£¬»¹ÊÇÓÃÁËcomposition-apiÖеÄAPI¶ÔÓ¦´¦Àí¡£

1 composition-api reactive

Reactive Ï൱ÓÚµ±Ç°µÄ Vue.observable () API£¬¾­¹ýreactive´¦ÀíºóµÄº¯ÊýÄܱä³ÉÏìӦʽµÄÊý¾Ý£¬ÀàËÆÓÚoption apiÀïÃæµÄvue´¦Àídataº¯ÊýµÄ·µ»ØÖµ¡£

ÎÒÃÇÓÃÒ»¸ötodoListµÄdemoÊÔ×ų¢³¢ÏÊ¡£

const { reactive , onMounted } = Vue
setup(){
const state = reactive({
count:0,
todoList:[]
})
/* ÉúÃüÖÜÆÚmounted */
onMounted(() => {
console.log('mounted')
})
/* Ôö¼ÓcountÊýÁ¿ */
function add(){
state.count++
}
/* ¼õÉÙcountÊýÁ¿ */
function del(){
state.count--
}
/* Ìí¼Ó´ú°ìÊÂÏî */
function addTodo(id,title,content){
state.todoList.push({
id,
title,
content,
done:false
})
}
/* Íê³É´ú°ìÊÂÏî */
function complete(id){
for(let i = 0; i< state.todoList.length; i++){
const currentTodo = state.todoList[i]
if(id === currentTodo.id){
state.todoList[i] = {
...currentTodo,
done:true
}
break
}
}
}
return {
state,
add,
del,
addTodo,
complete
}
}

2 options data

optionsÐÎʽµÄºÍvue2.0²¢Ã»ÓÐÊ²Ã´Çø±ð

export default {
data(){
return{
count:0,
todoList:[]
}
},
mounted(){
console.log('mounted')
}
methods:{
add(){
this.count++
},
del(){
this.count--
},
addTodo(id,title,content){
this.todoList.push({
id,
title,
content,
done:false
})
},
complete(id){
for(let i = 0; i< this.todoList.length; i++){
const currentTodo = this.todoList[i]
if(id === currentTodo.id){
this.todoList[i] = {
...currentTodo,
done:true
}
break
}
}
}
}
}

Èý ÏìӦʽԭÀí³õ̽

²»Í¬ÀàÐ͵ÄReactive

vue3.0¿ÉÒÔ¸ù¾ÝÒµÎñÐèÇóÒý½ø²»Í¬µÄAPI·½·¨¡£ÕâÀïÐèÒª

¢Ù reactive

½¨Á¢ÏìӦʽreactive£¬·µ»Øproxy¶ÔÏó£¬Õâ¸öreactive¿ÉÒÔÉî²ã´ÎµÝ¹é£¬Ò²¾ÍÊÇÈç¹û·¢ÏÖÕ¹¿ªµÄÊôÐÔÖµÊÇÒýÓÃÀàÐ͵ĶøÇÒ±»ÒýÓ㬻¹»áÓÃreactiveµÝ¹é´¦Àí¡£¶øÇÒÊôÐÔÊÇ¿ÉÒÔ±»Ð޸ĵġ£

¢Ú shallowReactive

½¨Á¢ÏìӦʽshallowReactive£¬·µ»Øproxy¶ÔÏ󡣺ÍreactiveµÄÇø±ðÊÇÖ»½¨Á¢Ò»²ãµÄÏìӦʽ£¬Ò²¾ÍÊÇ˵Èç¹û·¢ÏÖÕ¹¿ªÊôÐÔÊÇÒýÓÃÀàÐÍÒ²²»»áµÝ¹é¡£

¢Û readonly

·µ»ØµÄproxy´¦ÀíµÄ¶ÔÏ󣬿ÉÒÔÕ¹¿ªµÝ¹é´¦Àí£¬µ«ÊÇÊôÐÔÊÇÖ»¶ÁµÄ£¬²»ÄÜÐ޸ġ£¿ÉÒÔ×öprops´«µÝ¸ø×Ó×é¼þʹÓá£

¢Ü shallowReadonly

·µ»Ø¾­¹ý´¦ÀíµÄproxy¶ÔÏ󣬵«Êǽ¨Á¢ÏìӦʽÊôÐÔÊÇÖ»¶ÁµÄ£¬²»Õ¹¿ªÒýÓÃÒ²²»µÝ¹éת»»£¬¿ÉÒÔÕâÓÃÓÚΪÓÐ״̬×é¼þ´´½¨props´úÀí¶ÔÏó¡£

const rawToReactive = new WeakMap<any, any>()
const reactiveToRaw = new WeakMap<any, any>()
const rawToReadonly = new WeakMap<any, any>() /* Ö»¶ÁµÄ */
const readonlyToRaw = new WeakMap<any, any>() /* Ö»¶ÁµÄ */

´¢´æ¶ÔÏóÓëproxy

ÉÏÎÄÖÐÎÒÃÇÌá¼°µ½¡£ÓÃReactive´¦Àí¹ý²¢·µ»ØµÄ¶ÔÏóÊÇÒ»¸öproxy¶ÔÏ󣬼ÙÉè´æÔںܶà×é¼þ£¬»òÕßÔÚÒ»¸ö×é¼þÖб»¶à´Îreactive£¬¾Í»áÓкܶà¶Ôproxy¶ÔÏóºÍËü´úÀíµÄÔ­¶ÔÏó¡£ÎªÁËÄܰÑproxy¶ÔÏóºÍÔ­¶ÔÏó½¨Á¢¹ØÏµ£¬vue3.0²ÉÓÃÁËWeakMapÈ¥´¢´æÕâЩ¶ÔÏó¹ØÏµ¡£WeakMaps ±£³ÖÁ˶ԼüÃûËùÒýÓõĶÔÏóµÄÈõÒýÓ㬼´À¬»ø»ØÊÕ»úÖÆ²»½«¸ÃÒýÓÿ¼ÂÇÔÚÄÚ¡£Ö»ÒªËùÒýÓõĶÔÏóµÄÆäËûÒýÓö¼±»Çå³ý£¬À¬»ø»ØÊÕ»úÖÆ¾Í»áÊͷŸöÔÏóËùÕ¼ÓõÄÄÚ´æ¡£Ò²¾ÍÊÇ˵£¬Ò»µ©²»ÔÙÐèÒª£¬WeakMap ÀïÃæµÄ¼üÃû¶ÔÏóºÍËù¶ÔÓ¦µÄ¼üÖµ¶Ô»á×Ô¶¯Ïûʧ£¬²»ÓÃÊÖ¶¯É¾³ýÒýÓá£

vue3.0 ÓÃreadonlyÀ´ÉèÖñ»À¹½ØÆ÷À¹½ØµÄ¶ÔÏóÄÜ·ñ±»Ð޸ģ¬¿ÉÒÔÂú×ã֮ǰµÄprops²»Äܱ»Ð޸ĵĵ¥ÏòÊý¾ÝÁ÷³¡¾°¡£

ÎÒÃǽÓÏÂÀ´Öص㽲һϽÓÏÂÀ´µÄËĸöweakMapµÄ´¢´æ¹ØÏµ¡£

rawToReactive

¼üÖµ¶Ô £º { [targetObject] : obseved }

target£¨¼ü£©:Ä¿±ê¶ÔÏóÖµ(ÕâÀï¿ÉÒÔÀí½âΪ**reactive**µÄµÚÒ»¸ö²ÎÊý¡£)

obsered£¨Öµ£©:¾­¹ýproxy´úÀíÖ®ºóµÄproxy¶ÔÏó¡£

reactiveToRaw

reactiveToRaw ´¢´æµÄ¸ÕºÃÓë rawToReactiveµÄ¼üÖµ¶ÔÊÇÏà·´µÄ¡£

¼üÖµ¶Ô { [obseved] : targetObject }

rawToReadonly

¼üÖµ¶Ô £º { [target] : obseved }

target£¨¼ü£©£ºÄ¿±ê¶ÔÏó¡£

obsered£¨Öµ£©:¾­¹ýproxy´úÀíÖ®ºóµÄÖ»¶ÁÊôÐÔµÄproxy¶ÔÏó¡£

readonlyToRaw

´¢´æ×´Ì¬ÓërawToReadonly¸ÕºÃÏà·´¡£

reactiveÈë¿Ú½âÎö

½ÓÏÂÀ´ÎÒÃÇÖØµã´Óreactive¿ªÊ¼½²¡£

reactive({ ...object }) Èë¿Ú

export function reactive(target: object) {
if (readonlyToRaw.has(target)) {
return target
}
return createReactiveObject(
target, /* Ä¿±ê¶ÔÏó */
rawToReactive, /* { [targetObject] : obseved } */
reactiveToRaw, /* { [obseved] : targetObject } */
mutableHandlers, /* ´¦Àí »ù±¾Êý¾ÝÀàÐÍ ºÍ ÒýÓÃÊý¾ÝÀàÐÍ */
mutableCollectionHandlers /* ÓÃÓÚ´¦Àí Set, Map, WeakMap, WeakSet ÀàÐÍ */
)
}

reactiveº¯ÊýµÄ×÷ÓþÍÊÇͨ¹ýcreateReactiveObject·½·¨²úÉúÒ»¸öproxy,¶øÇÒÕë¶Ô²»Í¬µÄÊý¾ÝÀàÐ͸ø¶¨Á˲»Í¬µÄ´¦Àí·½·¨¡£

createReactiveObject

֮ǰ˵µ½µÄcreateReactiveObject£¬ÎÒÃǽÓÏÂÀ´¿´¿´createReactiveObject·¢ÉúÁËʲô¡£

const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
function createReactiveObject(
target: unknown,
toProxy: WeakMap<any, any>,
toRaw: WeakMap<any, any>,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
/* ÅжÏÄ¿±ê¶ÔÏóÊÇ·ñ±»effect */
/* observed Ϊ¾­¹ý new Proxy´úÀíµÄº¯Êý */
let observed = toProxy.get(target) /* { [target] : obseved } */
if (observed !== void 0) { /* Èç¹ûÄ¿±ê¶ÔÏóÒѾ­±»ÏìӦʽ´¦Àí£¬ÄÇôֱ½Ó·µ»ØproxyµÄobserved¶ÔÏó */
return observed
}
if (toRaw.has(target)) { /* { [observed] : target } */
return target
}
/* Èç¹ûÄ¿±ê¶ÔÏóÊÇ Set, Map, WeakMap, WeakSet ÀàÐÍ£¬ÄÇô handerº¯ÊýÊÇ collectionHandlers ·ñ²àÄ¿±êº¯ÊýÊÇbaseHandlers */
const handlers = collectionTypes.has(target.constructor)
? collectionHandlers
: baseHandlers
/* TODO: ´´½¨ÏìӦʽ¶ÔÏó */
observed = new Proxy(target, handlers)
/* target ºÍ observed ½¨Á¢¹ØÁª */
toProxy.set(target, observed)
toRaw.set(observed, target)
/* ·µ»Øobserved¶ÔÏó */
return observed
}

ͨ¹ýÉÏÃæÔ´Âë´´½¨proxy¶ÔÏóµÄ´óÖÂÁ÷³ÌÊÇÕâÑùµÄ£º

¢ÙÊ×ÏÈÅжÏÄ¿±ê¶ÔÏóÓÐûÓб»proxyÏìӦʽ´úÀí¹ý£¬Èç¹ûÊÇÄÇôֱ½Ó·µ»Ø¶ÔÏó¡£

¢ÚÈ»ºóͨ¹ýÅжÏÄ¿±ê¶ÔÏóÊÇ·ñÊÇ[ Set, Map, WeakMap, WeakSet ]Êý¾ÝÀàÐÍÀ´Ñ¡ÔñÊÇÓÃcollectionHandlers £¬ »¹ÊÇbaseHandlers->¾ÍÊÇreactive´«½øÀ´µÄmutableHandlers×÷ΪproxyµÄhander¶ÔÏó¡£

¢Û×îºóͨ¹ýÕæÕýʹÓÃnew proxyÀ´´´½¨Ò»¸öobserved £¬È»ºóͨ¹ýrawToReactive reactiveToRaw ±£´æ targetºÍobserved¼üÖµ¶Ô¡£

´óÖÂÁ÷³Ìͼ£º

ËÄ À¹½ØÆ÷¶ÔÏóbaseHandlers -> mutableHandlers

֮ǰÎÒÃǽéÉܹýbaseHandlers¾ÍÊǵ÷ÓÃreactive·½·¨createReactiveObject´«½øÀ´µÄmutableHandlers¶ÔÏó¡£

ÎÒÃÇÏÈÀ´¿´Ò»ÏÂmutableHandlers¶ÔÏó

mutableHandlers

À¹½ØÆ÷µÄ×÷ÓÃÓò

export const mutableHandlers: ProxyHandler<object> = {
get,
set,
deleteProperty,
has,
ownKeys
}

vue3.0 Óõ½ÁËÒÔÉϼ¸¸öÀ¹½ØÆ÷¡£

¢Ùget,¶ÔÊý¾ÝµÄ¶ÁÈ¡ÊôÐÔ½øÐÐÀ¹½Ø£¬°üÀ¨ target.µãÓï·¨ ºÍ target[]

¢Úset£¬¶ÔÊý¾ÝµÄ´æÈëÊôÐÔ½øÐÐÀ¹½Ø ¡£

¢ÛdeleteProperty delete²Ù×÷·û½øÐÐÀ¹½Ø¡£

vue2.0²»ÄܶԶÔÏóµÄdelete²Ù×÷·û½øÐÐÊôÐÔÀ¹½Ø¡£

Àý×Ó £º

delete object.a

ÊÇÎÞ·¨¼à²âµ½µÄ¡£

vue3.0proxyÖÐdeleteProperty ¿ÉÒÔÀ¹½Ø delete ²Ù×÷·û£¬Õâ¾Í±íÊövue3.0ÏìӦʽ¿ÉÒÔ¼àÌýµ½ÊôÐÔµÄɾ³ý²Ù×÷¡£

¢Ühas£¬¶Ô in ²Ù×÷·û½øÐÐÊôÐÔÀ¹½Ø¡£

vue2.0²»ÄܶԶÔÏóµÄin²Ù×÷·û½øÐÐÊôÐÔÀ¹½Ø¡£

Àý×Ó

a in object

has ÊÇΪÁ˽â¾öÈçÉÏÎÊÌâ¡£Õâ¾Í±íʾÁËvue3.0¿ÉÒÔ¶Ô in ²Ù×÷·û*½øÐÐÀ¹½Ø¡£

¢ÝownKeys Object.keys(proxy) ,for...in...Ñ­»· ,Object.getOwnPropertySymbols(proxy) £¬ Object.getOwnPropertyNames(proxy)À¹½ØÆ÷

Àý×Ó

Object.keys(object)

˵Ã÷vue3.0¿ÉÒÔ¶ÔÒÔÉÏÕâЩ·½·¨½øÐÐÀ¹½Ø¡£

Îå ×é¼þ³õʼ»¯½×¶Î

Èç¹ûÎÒÃÇÏëҪŪÃ÷°×Õû¸öÏìӦʽԭÀí¡£ÄÇô×é¼þ³õʼ»¯£¬µ½³õʼ»¯¹ý³ÌÖÐcomposition-apiµÄreactive´¦Àídata£¬ÒÔ¼°±àÒë½×¶Î¶ÔdataÊôÐÔ½øÐÐÒÀÀµÊÕ¼¯ÊÇ·Ö²»¿ªµÄ¡£vue3.0ÌṩÁËÒ»Ì×´Ó³õʼ»¯£¬µ½render¹ý³ÌÖÐÒÀÀµÊÕ¼¯£¬µ½×é¼þ¸üÐÂ,µ½×é¼þÏú»ÙÍêÕûÏìӦʽÌåϵ£¬ÎÒÃǺÜÄÑ´ÓÒ»¸ö½Ç¶È°Ñ¶«Î÷½²Ã÷°×£¬ËùÒÔÔÚÕýʽ½²À¹½ØÆ÷¶ÔÏóÈçºÎÊÕ¼¯ÒÀÀµ£¬ÅÉ·¢¸üÐÂ֮ǰ£¬ÎÒÃÇ¿´¿´effect×öÁËЩʲô²Ù×÷

1 effect -> еÄäÖȾwatcher

vue3.0ÓÃeffect¸±×÷Óù³×ÓÀ´´úÌævue2.0watcher¡£ÎÒÃǶ¼ÖªµÀÔÚvue2.0ÖУ¬ÓÐäÖȾwatcherרߺÔðÊý¾Ý±ä»¯ºóµÄ´ÓÐÂäÖȾÊÓͼ¡£vue3.0¸ÄÓÃeffectÀ´´úÌæwatcher´ïµ½Í¬ÑùµÄЧ¹û¡£

ÎÒÃÇÏȼòµ¥½éÉÜÒ»ÏÂmountComponentÁ÷³Ì£¬ºóÃæµÄÎÄÕ»áÏêϸ½éÉÜmount½×¶ÎµÄ

1 mountComponent ³õʼ»¯mountComponent

// ³õʼ»¯×é¼þ
const mountComponent: MountComponentFn = (
initialVNode,
container,
anchor,
parentComponent,
parentSuspense,
isSVG,
optimized
) => {
/* µÚÒ»²½: ´´½¨component ʵÀý */
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
initialVNode,
parentComponent,
parentSuspense
))

/* µÚ¶þ²½ £º TODO:³õʼ»¯ ³õʼ»¯×é¼þ,½¨Á¢proxy , ¸ù¾Ý×Ö·û´ÜÄ£°æµÃµ½ */
setupComponent(instance)
/* µÚÈý²½£º½¨Á¢Ò»¸öäÖȾeffect£¬Ö´ÐÐeffect */
setupRenderEffect(
instance, // ×é¼þʵÀý
initialVNode, //vnode
container, // ÈÝÆ÷ÔªËØ
anchor,
parentSuspense,
isSVG,
optimized
)
}

ÉÏÃæÊÇÕû¸ömountComponentµÄÖ÷Òª·ÖΪÁËÈý²½£¬ÎÒÃÇÕâÀï·Ö±ð½éÉÜÒ»ÏÂÿ¸ö²½Öè¸ÉÁËʲô£º

¢Ù µÚÒ»²½: ´´½¨component ʵÀý ¡£

¢Ú µÚ¶þ²½£º³õʼ»¯×é¼þ,½¨Á¢proxy ,¸ù¾Ý×Ö·û´ÜÄ£°æµÃµ½renderº¯Êý¡£ÉúÃüÖÜÆÚ¹³×Óº¯Êý´¦ÀíµÈµÈ

¢Û µÚÈý²½£º½¨Á¢Ò»¸öäÖȾeffect£¬Ö´ÐÐeffect¡£

´ÓÈçÉÏ·½·¨ÖÐÎÒÃÇ¿ÉÒÔ¿´µ½£¬ÔÚsetupComponentÒѾ­¹¹½¨ÁËÏìӦʽ¶ÔÏ󣬵«ÊÇ»¹Ã»Óгõʼ»¯ÊÕ¼¯ÒÀÀµ¡£

2 setupRenderEffect ¹¹½¨äÖȾeffect

const setupRenderEffect: SetupRenderEffectFn = (
instance,
initialVNode,
container,
anchor,
parentSuspense,
isSVG,
optimized
) => {
/* ´´½¨Ò»¸öäÖȾ effect */
instance.update = effect(function componentEffect() {
//...ʡȥµÄÄÚÈݺóÃæ»á½²µ½
},{ scheduler: queueJob })
}

ΪÁËÈôó¼Ò¸üÇå³þµÄÃ÷°×ÏìӦʽԭÀí£¬ÎÒÕâÖ»±£ÁôÁ˺ÍÏìӦʽԭÀíÓйØÏµµÄ²¿·Ö´úÂë¡£

setupRenderEffectµÄ×÷ÓÃ

¢Ù ´´½¨Ò»¸öeffect£¬²¢°ÑËü¸³Öµ¸ø×é¼þʵÀýµÄupdate·½·¨£¬×÷ΪäÖȾ¸üÐÂÊÓͼÓá£

¢Ú componentEffect×÷Ϊ»Øµ÷º¯ÊýÐÎʽ´«µÝ¸øeffect×÷ΪµÚÒ»¸ö²ÎÊý

3 effect×öÁËЩʲô

export function effect<T = any>(
fn: () => T,
options: ReactiveEffectOptions = EMPTY_OBJ
): ReactiveEffect<T> {
const effect = createReactiveEffect(fn, options)
/* Èç¹û²»ÊÇÀÁ¼ÓÔØ Á¢¼´Ö´ÐÐ effectº¯Êý */
if (!options.lazy) {
effect()
}
return effect
}

effect×÷ÓÃÈçÏÂ

¢Ù Ê×Ïȵ÷Óá£createReactiveEffect.

¢Ú Èç¹û²»ÊÇÀÁ¼ÓÔØ Á¢¼´Ö´ÐÐ ÓÉcreateReactiveEffect´´½¨³öÀ´µÄReactiveEffectº¯Êý¡£

4 ReactiveEffect

function createReactiveEffect<T = any>(
fn: (...args: any[]) => T, /**»Øµ÷º¯Êý */
options: ReactiveEffectOptions
): ReactiveEffect<T> {
const effect = function reactiveEffect(...args: unknown[]): unknown {
try {
enableTracking()
effectStack.push(effect) //ÍùeffectÊý×éÖÐÀï·ÅÈ뵱ǰ effect
activeEffect = effect //TODO: effect ¸³Öµ¸øµ±Ç°µÄ activeEffect
return fn(...args) //TODO: fn Ϊeffect´«½øÀ´ componentEffect
} finally {
effectStack.pop() //Íê³ÉÒÀÀµÊÕ¼¯ºó´ÓeffectÊý×éɾµôÕâ¸ö effect
resetTracking()
/* ½«activeEffect»¹Ô­µ½Ö®Ç°µÄeffect */
activeEffect = effectStack[effectStack.length - 1]
}
} as ReactiveEffect
/* ÅäÖÃһϳõʼ»¯²ÎÊý */
effect.id = uid++
effect._isEffect = true
effect.active = true
effect.raw = fn
effect.deps = [] /* TODO:ÓÃÓÚÊÕ¼¯Ïà¹ØÒÀÀµ */
effect.options = options
return effect
}

createReactiveEffectµÄ×÷ÓÃÖ÷ÒªÊÇÅäÖÃÁËһЩ³õʼ»¯µÄ²ÎÊý£¬È»ºó°ü×°ÁË֮ǰ´«½øÀ´µÄfnÖØÒªµÄÒ»µãÊǰѵ±Ç°µÄeffect¸³Öµ¸øÁËactiveEffect,ÕâÒ»µã·Ç³£ÖØÒª£¬ºÍÊÕ¼¯ÒÀÀµÓÐ×ÅÖ±½ÓµÄ¹ØÏµ

×ܽá

ÎÒÃÇÕâÀï¸öÏìӦʽ³õʼ»¯½×¶Î½øÐÐ×ܽá

¢Ù setupComponent´´½¨×é¼þ£¬µ÷ÓÃcomposition-api,´¦Àíoptions£¨¹¹½¨ÏìӦʽ£©µÃµ½Observer¶ÔÏó¡£

¢Ú ´´½¨Ò»¸öäÖȾeffect£¬ÀïÃæ°ü×°ÁËÕæÕýµÄäÖȾ·½·¨componentEffect£¬Ìí¼ÓһЩeffect³õʼ»¯ÊôÐÔ¡£

¢Û È»ºóÁ¢¼´Ö´ÐÐeffect£¬È»ºó½«µ±Ç°äÖȾeffect¸³Öµ¸øactiveEffect

×îºóÎÒÃÇÓÃÒ»ÕÅͼÀ´½âÊÍÒ»ÏÂÕû¸öÁ÷³Ì¡£

Áù ÒÀÀµÊÕ¼¯£¬get×öÁËЩʲô£¿

1 »Ø¹émutableHandlersÖеÄget·½·¨

1 ²»Í¬ÀàÐ͵Äget

/* Éî¶Èget */
const get = /*#__PURE__*/ createGetter()
/* dzget */
const shallowGet = /*#__PURE__*/ createGetter(false, true)
/* Ö»¶ÁµÄget */
const readonlyGet = /*#__PURE__*/ createGetter(true)
/* Ö»¶ÁµÄdzget */
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)

ÉÏÃæÎÒÃÇ¿ÉÒÔÖªµÀ£¬¶ÔÓÚ֮ǰ½²µÄËÄÖÖ²»Í¬µÄ½¨Á¢ÏìӦʽ·½·¨£¬¶ÔÓ¦ÁËËÄÖÖ²»Í¬µÄget,ÏÂÃæÊÇÒ»Ò»¶ÔÓ¦¹ØÏµ¡£

reactive ---------> get

shallowReactive --------> shallowGet

readonly ----------> readonlyGet

shallowReadonly ---------------> shallowReadonlyGet

ËÄÖÖ·½·¨¶¼Êǵ÷ÓÃÁËcreateGetter·½·¨£¬Ö»²»¹ýÊDzÎÊýµÄÅäÖò»Í¬£¬ÎÒÃÇÕâÀïÄǵÚÒ»¸öget·½·¨×ö²Î¿¼£¬½ÓÏÂÀ´Ì½Ë÷Ò»ÏÂcreateGetter¡£

function createGetter(isReadonly = false, shallow = false) {
return function get(target: object, key: string | symbol, receiver: object) {
const res = Reflect.get(target, key, receiver)
/* dzÂß¼­ */
if (shallow) {
!isReadonly && track(target, TrackOpTypes.GET, key)
return res
}
/* Êý¾Ý°ó¶¨ */
!isReadonly && track(target, TrackOpTypes.GET, key)
return isObject(res)
? isReadonly
?
/* Ö»¶ÁÊôÐÔ */
readonly(res)
/* */
: reactive(res)
: res
}
}

Õâ¾ÍÊÇcreateGetterÖ÷ÒªÁ÷³Ì£¬ÌØÊâµÄÊý¾ÝÀàÐͺÍre*ÎÒÃÇÔÝʱÏȲ»¿¼ÂÇ¡£

ÕâÀïÓÃÁËһЩÁ÷³ÌÅжϣ¬ÎÒÃÇÓÃÁ÷³ÌͼÀ´ËµÃ÷Ò»ÏÂÕâ¸öº¯ÊýÖ÷Òª×öÁËʲô£¿

ÎÒÃÇ¿ÉÒԵóö½áÂÛ£º

ÔÚvue2.0µÄʱºò¡£ÏìӦʽÊÇÔÚ³õʼ»¯µÄʱºò¾ÍÉî²ã´ÎµÝ¹é´¦ÀíÁË

µ«ÊÇ

Óëvue2.0²»Í¬µÄÊÇ,¼´±ãÊÇÉî¶ÈÏìӦʽÎÒÃÇÒ²Ö»ÄÜÔÚ»ñÈ¡ÉÏÒ»¼¶getÖ®ºó²ÅÄÜ´¥·¢ÏÂÒ»¼¶µÄÉî¶ÈÏìӦʽ¡£

±ÈÈç

setup(){
const state = reactive({ a:{ b:{} } })
return {
state
}
}

ÔÚ³õʼ»¯µÄʱºò£¬Ö»ÓÐaµÄÒ»²ã¼¶½¨Á¢ÁËÏìӦʽ£¬b²¢Ã»Óн¨Á¢ÏìӦʽ£¬¶øµ±ÎÒÃÇÓÃstate.aµÄʱºò£¬²Å»áÕæÕýµÄ½«bÒ²×öÏìӦʽ´¦Àí£¬Ò²¾ÍÊÇ˵ÎÒÃÇ·ÃÎÊÁËÉÏÒ»¼¶ÊôÐÔºó£¬ÏÂÒ»´úÊôÐԲŻáÕæÕýÒâÒåÉϽ¨Á¢ÏìӦʽ

ÕâÑù×öºÃ´¦ÊÇ£¬

1 ³õʼ»¯µÄʱºò²»ÓõݹéÈ¥´¦Àí¶ÔÏó£¬Ôì³ÉÁ˲»±ØÒªµÄÐÔÄÜ¿ªÏú¡£

2 ÓÐһЩûÓÐÓÃÉϵÄstate£¬ÕâÀï¾Í²»ÐèÒªÔÚÉî²ã´ÎÏìӦʽ´¦Àí¡£

2 track->ÒÀÀµÊÕ¼¯Æ÷

ÎÒÃÇÏÈÀ´¿´¿´trackÔ´Â룺

track×öÁËЩʲô

/* target ¶ÔÏó±¾Éí £¬keyÊôÐÔÖµ type Ϊ 'GET' */
export function track(target: object, type: TrackOpTypes, key: unknown) {
/* µ±´òÓ¡»òÕß»ñÈ¡ÊôÐÔµÄʱºò console.log(this.a) ÊÇûÓÐactiveEffectµÄ µ±Ç°·µ»ØÖµÎª0 */
let depsMap = targetMap.get(target)
if (!depsMap) {
/* target -map-> depsMap */
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
/* key : dep dep¹Û²ìÕß */
depsMap.set(key, (dep = new Set()))
}
/* µ±Ç°activeEffect */
if (!dep.has(activeEffect)) {
/* depÌí¼Ó activeEffect */
dep.add(activeEffect)
/* ÿ¸ö activeEffectµÄdeps ´æ·Åµ±Ç°µÄdep */
activeEffect.deps.push(dep)
}
}

ÀïÃæÖ÷ÒªÒýÈëÁËÁ½¸ö¸ÅÄî targetMapºÍ depsMap

targetMap

¼üÖµ¶Ô proxy : depsMap

proxy £º Ϊreactive´úÀíºóµÄ Observer¶ÔÏó ¡£

depsMap £ºÎª´æ·ÅÒÀÀµdepµÄ map Ó³Éä¡£

depsMap

¼üÖµ¶Ô£ºkey : deps

key Ϊµ±Ç°get·ÃÎʵÄÊôÐÔÃû£¬

deps ´æ·ÅeffectµÄsetÊý¾ÝÀàÐÍ¡£

ÎÒÃÇÖªµÀtrack×÷ÓôóÖÂÊÇ£¬Ê×Ïȸù¾Ý proxy¶ÔÏ󣬻ñÈ¡´æ·ÅdepsµÄdepsMap£¬È»ºóͨ¹ý·ÃÎʵÄÊôÐÔÃûkey»ñÈ¡¶ÔÓ¦µÄdep,È»ºó½«µ±Ç°¼¤»îµÄeffect´æÈ뵱ǰdepÊÕ¼¯ÒÀÀµ¡£

Ö÷Òª×÷ÓÃ

¢ÙÕÒµ½Ó뵱ǰproxy ºÍ key¶ÔÓ¦µÄdep¡£

¢ÚdepÓ뵱ǰactiveEffect½¨Á¢ÁªÏµ£¬ÊÕ¼¯ÒÀÀµ¡£

ΪÁË·½±ãÀí½â£¬targetMap ºÍ depsMapµÄ¹ØÏµ£¬ÏÂÃæÎÒÃÇÓÃÒ»¸öÀý×ÓÀ´ËµÃ÷£º

Àý×Ó£º

¸¸×é¼þA

<div id="app" >
<span>{{ state.a }}</span>
<span>{{ state.b }}</span>
<div>
<script>
const { createApp, reactive } = Vue

/* ×Ó×é¼þ */
const Children ={
template="<div> <span>{{ state.c }}</span> </div>",
setup(){
const state = reactive({
c:1
})
return {
state
}
}
}
/* ¸¸×é¼þ */
createApp({
component:{
Children
}
setup(){
const state = reactive({
a:1,
b:2
})
return {
state
}
}
})mount('#app')

</script>

ÎÒÃÇÓÃÒ»·ùͼ±íʾÈçÉϹØÏµ£º

äÖȾeffectº¯ÊýÈçºÎ´¥·¢get

ÎÒÃÇÔÚÇ°ÃæËµ¹ý£¬´´½¨Ò»¸öäÖȾrenderEffect£¬È»ºó°Ñ¸³Öµ¸øactiveEffect£¬×îºóÖ´ÐÐrenderEffect £¬ÔÚÕâ¸öÆÚ¼äÊÇÔõô×öÒÀÀµÊÕ¼¯µÄÄØ£¬ÈÃÎÒÃÇÒ»ÆðÀ´¿´¿´,updateº¯ÊýÖÐ×öÁËʲô£¬ÎÒÃǻص½Ö®Ç°½²µÄcomponentEffectÂß¼­ÉÏÀ´

function componentEffect() {
if (!instance.isMounted) {
let vnodeHook: VNodeHook | null | undefined
const { el, props } = initialVNode
const { bm, m, a, parent } = instance
/* TODO: ´¥·¢instance.renderº¯Êý£¬ÐγÉÊ÷½á¹¹ */
const subTree = (instance.subTree = renderComponentRoot(instance))
if (bm) {
//´¥·¢ beforeMountÉùÃ÷ÖÜÆÚ¹³×Ó
invokeArrayFns(bm)
}
patch(
null,
subTree,
container,
anchor,
instance,
parentSuspense,
isSVG
)
/* ´¥·¢ÉùÃ÷ÖÜÆÚ mounted¹³×Ó */
if (m) {
queuePostRenderEffect(m, parentSuspense)
}
instance.isMounted = true
} else {
// ¸üÐÂ×é¼þÂß¼­
// ......
}
}

Õâ±ß´úÂë´óÖÂÊ×ÏÈ»áͨ¹ýrenderComponentRoot·½·¨ÐγÉÊ÷½á¹¹£¬ÕâÀïҪעÒâµÄÊÇ£¬ÎÒÃÇÔÚ×î³õmountComponentµÄsetupComponent·½·¨ÖУ¬ÒѾ­Í¨¹ý±àÒë·½·¨compile±àÒëÁËtemplateÄ£°æµÄÄÚÈÝ£¬state.a state.bµÈ³éÏóÓï·¨Ê÷£¬×îÖÕ·µ»ØµÄrenderº¯ÊýÔÚÕâ¸ö½×¶Î»á±»´¥·¢£¬ÔÚrenderº¯ÊýÖÐÔÚÄ£°æÖеıí´ïʽ state.a state.b µãÓï·¨»á±»Ìæ»»³ÉdataÖÐÕæÊµµÄÊôÐÔ£¬Õâʱºò¾Í½øÐÐÁËÕæÕýµÄÒÀÀµÊÕ¼¯£¬´¥·¢ÁËget·½·¨¡£½ÓÏÂÀ´¾ÍÊÇ´¥·¢ÉúÃüÖÜÆÚ beforeMount ,È»ºó¶ÔÕû¸öÊ÷½á¹¹ÖØÐÂpatch,patchÍê±Ïºó£¬µ÷ÓÃmounted¹³×Ó

ÒÀÀµÊÕ¼¯Á÷³Ì×ܽá

¢Ù Ê×ÏÈÖ´ÐÐrenderEffect £¬¸³Öµ¸øactiveEffect £¬µ÷ÓÃrenderComponentRoot·½·¨£¬È»ºó´¥·¢renderº¯Êý¡£

¢Ú ¸ù¾Ýrenderº¯Êý£¬½âÎö¾­¹ýcompile£¬Óï·¨Ê÷´¦Àí¹ýºóµÄÄ£°æ±í´ïʽ£¬·ÃÎÊÕæÊµµÄdataÊôÐÔ£¬´¥·¢get¡£

¢Û get·½·¨Ê×ÏȾ­¹ý֮ǰ²»Í¬µÄreactive£¬Í¨¹ýtrack·½·¨½øÐÐÒÀÀµÊÕ¼¯¡£

¢Ü track·½·¨Í¨¹ýµ±Ç°proxy¶ÔÏótarget,ºÍ·ÃÎʵÄÊôÐÔÃûkeyÀ´ÕÒµ½¶ÔÓ¦µÄdep¡£

¢Ý ½«depÓ뵱ǰµÄactiveEffect½¨Á¢ÆðÁªÏµ¡£½«activeEffectѹÈëdepÊý×éÖУ¬£¨´ËʱµÄdepÖÐÒѾ­º¬Óе±Ç°×é¼þµÄäÖȾeffect,Õâ¾ÍÊÇÏìӦʽµÄ¸ù±¾Ô­Òò£©Èç¹ûÎÒÃÇ´¥·¢set£¬¾ÍÄÜÔÚÊý×éÖÐÕÒµ½¶ÔÓ¦µÄeffect£¬ÒÀ´ÎÖ´ÐС£

×îºóÎÒÃÇÓÃÒ»¸öÁ÷³ÌͼÀ´±í´ïÒ»ÏÂÒÀÀµÊÕ¼¯µÄÁ÷³Ì¡£

Æß set ÅÉ·¢¸üÐÂ

½ÓÏÂÀ´ÎÒÃÇset²¿·ÖÂß¼­¡£

const set = /*#__PURE__*/ createSetter()
/* dzÂß¼­ */
const shallowSet = /*#__PURE__*/ createSetter(true)

setÒ²ÊÇ·ÖÁ½¸öÂß¼­£¬setºÍshallowSet,Á½ÖÖ·½·¨¶¼ÊÇÓÉcreateSetter²úÉú£¬ÎÒÃÇÕâÀïÖ÷ÒªÒÔset½øÐÐÆÊÎö¡£

createSetter´´½¨set

function createSetter(shallow = false) {
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
const oldValue = (target as any)[key]
/* shallowSetÂß¼­ */

const hadKey = hasOwn(target, key)
const result = Reflect.set(target, key, value, receiver)
/* Åжϵ±Ç°¶ÔÏ󣬺ʹæÔÚreactiveToRaw ÀïÃæÊÇ·ñÏàµÈ */
if (target === toRaw(receiver)) {
if (!hadKey) { /* н¨ÊôÐÔ */
/* TriggerOpTypes.ADD -> add */
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
/* ¸Ä±äÔ­ÓÐÊôÐÔ */
/* TriggerOpTypes.SET -> set */
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}

createSetterµÄÁ÷³Ì´óÖÂÊÇÕâÑùµÄ

¢Ù Ê×ÏÈͨ¹ýtoRawÅжϵ±Ç°µÄproxy¶ÔÏóºÍ½¨Á¢ÏìӦʽ´æÈëreactiveToRawµÄproxy¶ÔÏóÊÇ·ñÏàµÈ¡£

¢Ú ÅжÏtargetÓÐûÓе±Ç°key,Èç¹û´æÔڵϰ£¬¸Ä±äÊôÐÔ£¬Ö´ÐÐtrigger(target, TriggerOpTypes.SET, key, value, oldValue)¡£

¢Û Èç¹ûµ±Ç°key²»´æÔÚ£¬ËµÃ÷ÊǸ³ÖµÐÂÊôÐÔ£¬Ö´ÐÐtrigger(target, TriggerOpTypes.ADD, key, value)

trigger

/* ¸ù¾ÝvalueÖµµÄ¸Ä±ä£¬´ÓeffectºÍcomputerÄóö¶ÔÓ¦µÄcallback £¬È»ºóÒÀ´ÎÖ´ÐÐ */
export function trigger(
target: object,
type: TriggerOpTypes,
key?: unknown,
newValue?: unknown,
oldValue?: unknown,
oldTarget?: Map<unknown, unknown> | Set<unknown>
) {
/* »ñÈ¡depssMap */
const depsMap = targetMap.get(target)
/* ûÓо­¹ýÒÀÀµÊÕ¼¯µÄ £¬Ö±½Ó·µ»Ø */
if (!depsMap) {
return
}
const effects = new Set<ReactiveEffect>() /* effect¹³×Ó¶ÓÁÐ */
const computedRunners = new Set<ReactiveEffect>() /* ¼ÆËãÊôÐÔ¶ÓÁÐ */
const add = (effectsToAdd: Set<ReactiveEffect> | undefined) => {
if (effectsToAdd) {
effectsToAdd.forEach(effect => {
if (effect !== activeEffect || !shouldTrack) {
if (effect.options.computed) { /* ´¦ÀícomputedÂß¼­ */
computedRunners.add(effect) /* ´¢´æ¶ÔÓ¦µÄdep */
} else {
effects.add(effect) /* ´¢´æ¶ÔÓ¦µÄdep */
}
}
})
}
}

add(depsMap.get(key))

const run = (effect: ReactiveEffect) => {
if (effect.options.scheduler) { /* ·Å½ø scheduler µ÷¶È*/
effect.options.scheduler(effect)
} else {
effect() /* ²»´æÔÚµ÷¶ÈÇé¿ö£¬Ö±½ÓÖ´ÐÐeffect */
}
}

//TODO: ±ØÐëÊ×ÏÈÔËÐмÆËãÊôÐԵĸüУ¬ÒÔ±ã¼ÆËãµÄgetter
//ÔÚÈκÎÒÀÀµÓÚËüÃǵÄÕý³£¸üÐÂeffectÔËÐÐ֮ǰ£¬¶¼¿ÉÄÜʧЧ¡£

computedRunners.forEach(run) /* ÒÀ´ÎÖ´ÐÐcomputedRunners »Øµ÷*/
effects.forEach(run) /* ÒÀ´ÎÖ´ÐÐ effect »Øµ÷£¨ TODO: ÀïÃæ°üÀ¨äÖȾeffect £©*/
}

ÎÒÃÇÕâÀï±£ÁôÁËtriggerµÄºËÐÄÂß¼­

¢Ù Ê×ÏÈ´ÓtargetMapÖУ¬¸ù¾Ýµ±Ç°proxyÕÒµ½ÓëÖ®¶ÔÓ¦µÄdepsMap¡£

¢Ú ¸ù¾ÝkeyÕÒµ½depsMapÖжÔÓ¦µÄdeps£¬È»ºóͨ¹ýadd·½·¨·ÖÀë³ö¶ÔÓ¦µÄeffect»Øµ÷º¯ÊýºÍcomputed»Øµ÷º¯Êý¡£

¢Û ÒÀ´ÎÖ´ÐÐcomputedRunners ºÍ effects ¶ÓÁÐÀïÃæµÄ»Øµ÷º¯Êý£¬Èç¹û·¢ÏÖÐèÒªµ÷¶È´¦Àí,·Å½øschedulerʼþµ÷¶È

ÖµµÃ×¢ÒâµÄµÄÊÇ£º

renderEffect£¬»¹ÓÐͨ¹ýeffectAPI½¨Á¢µÄeffect£¬ÒÔ¼°Í¨¹ýwatchÐγɵÄeffect¡£ÎÒÃÇÕâÀïÖ»¿¼Âǵ½äÖȾeffect¡£ÖÁÓÚºóÃæµÄÇé¿ö»áÔÚ½ÓÏÂÀ´µÄÎÄÕÂÖкʹó¼ÒÒ»Æð·ÖÏí¡£

ÎÒÃÇÓÃÒ»·ùÁ÷³Ìͼ˵Ã÷Ò»ÏÂset¹ý³Ì¡£

°Ë ×ܽá

ÎÒÃÇ×ܽáÒ»ÏÂÕû¸öÊý¾Ý°ó¶¨½¨Á¢ÏìӦʽ´óÖ·ÖΪÈý¸ö½×¶Î

1 ³õʼ»¯½×¶Î£º ³õʼ»¯½×¶Îͨ¹ý×é¼þ³õʼ»¯·½·¨ÐγɶÔÓ¦µÄproxy¶ÔÏó£¬È»ºóÐγÉÒ»¸ö¸ºÔðäÖȾµÄeffect¡£

2 getÒÀÀµÊÕ¼¯½×¶Î£ºÍ¨¹ý½âÎötemplate£¬Ìæ»»ÕæÊµdataÊôÐÔ£¬À´´¥·¢get,È»ºóͨ¹ýstack·½·¨£¬Í¨¹ýproxy¶ÔÏóºÍkeyÐγɶÔÓ¦µÄdeps£¬½«¸ºÔðäÖȾµÄeffect´æÈëdeps¡££¨Õâ¸ö¹ý³Ì»¹ÓÐÆäËûµÄeffect£¬±ÈÈçwatchEffect´æÈëdepsÖÐ £©¡£

3 setÅÉ·¢¸üн׶Σºµ±ÎÒÃÇ this[key] = value ¸Ä±äÊôÐÔµÄʱºò£¬Ê×ÏÈͨ¹ýtrigger·½·¨£¬Í¨¹ýproxy¶ÔÏóºÍkeyÕÒµ½¶ÔÓ¦µÄdeps£¬È»ºó¸ødeps·ÖÀà·Ö³ÉcomputedRunnersºÍeffect,È»ºóÒÀ´ÎÖ´ÐУ¬Èç¹ûÐèÒªµ÷¶ÈµÄ£¬Ö±½Ó·ÅÈëµ÷¶È¡£

 
   
2114 ´Îä¯ÀÀ       27
Ïà¹ØÎÄÕÂ

Éî¶È½âÎö£ºÇåÀíÀôúÂë
ÈçºÎ±àд³öÓµ±§±ä»¯µÄ´úÂë
ÖØ¹¹-ʹ´úÂë¸ü¼ò½àÓÅÃÀ
ÍŶÓÏîÄ¿¿ª·¢"±àÂë¹æ·¶"ϵÁÐÎÄÕÂ
Ïà¹ØÎĵµ

ÖØ¹¹-¸ÄÉÆ¼ÈÓдúÂëµÄÉè¼Æ
Èí¼þÖØ¹¹v2
´úÂëÕû½àÖ®µÀ
¸ßÖÊÁ¿±à³Ì¹æ·¶
Ïà¹Ø¿Î³Ì

»ùÓÚHTML5¿Í»§¶Ë¡¢Web¶ËµÄÓ¦Óÿª·¢
HTML 5+CSS ¿ª·¢
ǶÈëʽC¸ßÖÊÁ¿±à³Ì
C++¸ß¼¶±à³Ì
×îл¼Æ»®
DeepSeekÔÚÈí¼þ²âÊÔÓ¦ÓÃʵ¼ù 4-12[ÔÚÏß]
DeepSeek´óÄ£ÐÍÓ¦Óÿª·¢Êµ¼ù 4-19[ÔÚÏß]
UAF¼Ü¹¹ÌåϵÓëʵ¼ù 4-11[±±¾©]
AIÖÇÄÜ»¯Èí¼þ²âÊÔ·½·¨Óëʵ¼ù 5-23[ÉϺ£]
»ùÓÚ UML ºÍEA½øÐзÖÎöÉè¼Æ 4-26[±±¾©]
ÒµÎñ¼Ü¹¹Éè¼ÆÓ뽨ģ 4-18[±±¾©]
 
×îÐÂÎÄÕÂ
ÈçºÎÉè¼Æ¸ßÀ©Õ¹µÄÔÚÏßÍøÒ³ÖÆ×÷ƽ̨
electronÈëÃÅÐĵÃ
ʹÓà Electron ¹¹½¨×ÀÃæÓ¦ÓÃ
VUE.JS×é¼þ»¯¿ª·¢Êµ¼ù
ÉîÈëÀí½âJSCore
×îпγÌ
HTML 5 + CSS3 Ô­ÀíÓ뿪·¢Ó¦ÓÃ
Webǰ¶Ë¸ß¼¶¹¤³Ìʦ±Ø±¸¼¼ÄÜʵս
Vue´óÐÍÏîÄ¿¿ª·¢ÊµÕ½
ReactÔ­ÀíÓëʵ¼ù
Vue.js½ø½×Óë°¸Àýʵ¼ù
³É¹¦°¸Àý
Öн»¼¯ÍÅ ¹¹½¨Web×Ô¶¯»¯²âÊÔ¿ò¼Ü
ijָÃûµçÐŹ«Ë¾ Vue.js½ø½×Óë°¸Àý
¹úµçÍ¨ÍøÂç¼¼Êõ HTML5+CSS3 +webǰ¶Ë¿ò
ÒÆ¶¯Í¨ÐÅ ÒÆ¶¯»¥ÁªÍøÓ¦Óÿª·¢Ô­Àí
ijµçÁ¦ÐÐ android¿ª·¢Æ½Ì¨×î¼Ñ