Reactive
何为响应式对象,在我看来就是一个可以进行拦截的对象,vue2采用的是Object.defineProperty,vue3采用的是Proxy,至于vue3为什么要采用proxy这里我们不做过多解释,大家可自行了解。
单测
下面,跟着下面的单测一起来了解下reactive的具体功能点。
// src/reactivity/test/reactive.spec.ts
import {reactive} from '../reactive'
describe("reactive", () => {
it("happy path", () => {
const origin = {
foo: 1
}
const obj = reactive(origin)
expect(obj).not.toBe(origin)
expect(obj.foo).toBe(1)
})
})
在vue3里,直接通过一个reactive(obj)函数创建一个proxy对象,返回的对象属性和值都和obj保持一直,但他们属于不同的两个对象。
代码实现
根据上面单测的功能点,我们开始一步步的来实现我们的reactive函数。
创建./src/reactivity/reative.ts文件
1、导出一个reactive函数,接收用户传入的object数据。
export function reactive (raw) {
// write at this
}
2、返回一个Proxy实例
Proxy接收2个参数,第一个是需要劫持的object,第二个参数是一个options,这里我们只用设置get和set。
export function reactive (raw) {
return new Proxy(raw, {
get (target, key) {},
set (target, key, value) {}
})
}
3、处理get请求
当获取这个响应式对象的某个属性时调用,target就是获取的object,key就是获取的对象属性名称。
例如:obj.name,target代表obj,而key则代表name。
提示:这里的Reflect.get(target, key)其实就是获取target对象的key属性的值,最后在get中返回这个值即可。
get (target, key) {
const res = Reflect.get(target, key)
return res
}
4、处理set赋值
当执行了赋值操作时会调用set方法,target是操作的对象,key是操作对象的属性名称,value是赋值。
Reflect.set(target, key, value)即是给target对象的key属性赋值value,该执行结果是boolean,即代表赋值成功与否。
set (target, key, value) {
const res = Reflect.set(target, key, value)
return res
}
到这里,我们就成功创建了一个响应式对象,给这个响应式对象添加了set,和get操作。
代码报错
写完后发现我们的代码一直报错,可我们写的代码也没问题,这是因为typescript配置问题,在tsconfig.json中加上"lib": ["DOM", "ES6"]。
测试结果
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.889 s, estimated 1 s
Ran all test suites.
Done in 2.25s.
执行yarn test或者yarn test reactive,我们的测试没有报错,就说明我们的功能已经完成,如果有报错,请参考上面的步骤仔细检查。
总结
最后我们再一起来回顾一下这一节我们实现的代码及功能,在reactive.ts中我们导出了reactive函数,自身接收一个obj作为参数,并基于obj返回一个proxy对象,我们还简单的处理了一下proxy的get和set请求,后面我们将会对这个proxy对象进行完善,真正达到响应式。
下一节,我们将一起了解vue3的effect。