vue2
入口
src/core/instance/index.js
// 入口 initMixin
initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);
进入initMixin(Vue)方法
src/core/instance/init.js
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
进入initState(vm)方法。
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
该方法中检查了methods,props中和data可能的重名,最后执行以下逻辑
// observe data
observe(data, true /* asRootData */)
进入observe()方法
// 关键逻辑
// 非服务端渲染 非Object.freeze()处理
// 是数组或者普通对象
// Object.prototype.toString.call(new Set()) 返回 "[object Set]"
if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
在Observer的constructor中,区别了数组和
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
// 定义响应式
this.walk(value)
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
正文defineReactive
export function defineReactive(
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
// 例如传入 obj {message:'hello'} key:message
// 用于收集 Watcher
const dep = new Dep();
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return;
}
// cater for pre-defined getter/setters
const getter = property && property.get;
const setter = property && property.set;
if ((!getter || setter) && arguments.length === 2) {
val = obj[key];
}
let childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
// new Watcher 时 设置tagert为自己,获取data中指定值,触发get触发执行此逻辑。再将target置空
if (Dep.target) {
// 添加 Watcher
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value;
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== "production" && customSetter) {
customSetter();
}
// #7981: for accessor properties without setter
if (getter && !setter) return;
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
// 提示 调用watcher中update方法 queueWatcher(this)
dep.notify();
}
});
}
总结,watcher存放了对dom的操作,劫持属性get存储绑定wartcher。set是触发notify,watcher触发预存的操作。
react
react界面对数据的响应,大体是由setState触发的,引起布丁算法对比虚拟dom,然后转换为真实dom。 废话不多说上源码。
正文setState
Component.prototype.setState = function(partialState, callback) {
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
触发了updater定义的入队方法。
ReactPartialRenderer.js
ReactFiberClassComponent.new(old).js
中定义了自己的,后者代码为
enqueueSetState(inst, payload, callback) {
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
const lane = requestUpdateLane(fiber, suspenseConfig);
const update = createUpdate(eventTime, lane, suspenseConfig);
update.payload = payload;
if (callback !== undefined && callback !== null) {
if (__DEV__) {
warnOnInvalidCallback(callback, 'setState');
}
update.callback = callback;
}
enqueueUpdate(fiber, update);
scheduleUpdateOnFiber(fiber, lane, eventTime);
}
之后fiber和quene管理相关笔者未深究,后期补上。
vue3
吐槽,终于ts了
vue3定义想用响应数据如下
setup() {
// data
const state = reactive({
count: 0
});
reactive.ts
export function reactive(target: object) {
// isReadonly 属性不设置响应式
if (target && (target as Target)[ReactiveFlags.isReadonly]) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
)
}
createReactiveObject方法去掉一些判断的核心代码
const observed = new Proxy(
target,
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
)
def(
target,
isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive,
observed
)
这里我们大概先回忆下proxy 劫持的写法
this._data = new Proxy(data, {
set(target, prop, newVal) {
return Reflect.set(...arguments);
}
})
历史不支持的数据结构和一些判断也发生了变化
const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
const isObservableType = /*#__PURE__*/ makeMap(
'Object,Array,Map,Set,WeakMap,WeakSet'
)
const canObserve = (value: Target): boolean => {
return (
!value[ReactiveFlags.skip] &&
isObservableType(toRawType(value)) &&
!Object.isFrozen(value)
)
}
vue即使没有patch也能响应,其精准的针对了每个变量。 react需要patch去寻找虚拟dom的变化触发ui更新。
未完待续