实现 ref 函数
特点
ref 函数经常用来包装基本类型,也可以用来包装一个对象(不常用)
底层用的其实就是 Object.defineProperty
第 1 步
packages/reactivity/src/ref.ts
import { toReactive } from './reactive'
import { isTracking, trackEffects, triggerEffects } from './effect'
import { Dep } from './dep'
class RefImpl<T> {
public dep?: Dep = undefined
public __v_isRef = true
public _value: T
constructor(public _rowValue: T) {
// 如果 _rowValue 传进来的是一个对象,那么需要将对象转换成响应式
this._value = toReactive(_rowValue)
}
// 取值的时候进行依赖收集
get value() {
// 依赖收集
if (isTracking()) {
trackEffects(this.dep || (this.dep = new Set()))
}
return this._value
}
// 修改的时候触发依赖更新
set value(newValue) {
// 判断新值和老值是否相等,不相等再更改
if (newValue !== this._rowValue) {
this._rowValue = newValue
// 由于传的值可能是对象,所以在这里将其转换成 reactive
this._value = toReactive(newValue)
triggerEffects(this.dep!)
}
}
}
function createRef(value: unknown) {
return new RefImpl(value)
}
export function ref(value: unknown) {
return createRef(value)
}
packages/reactivity/src/index.ts
export { effect } from './effect'
export { reactive } from './reactive'
export { computed } from './computed'
// --------------------------新增 start------------------------
export { ref } from './ref'
// --------------------------新增 end--------------------------
packages/reactivity/example/ref.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="../dist/reactivity.global.js"></script>
<script>
const { effect, ref } = VueReactivity
const state = ref(0)
effect(() => {
console.log(state.value)
})
console.log(state)
setTimeout(() => {
state.value++
})
</script>
</body>
</html>
效果如下:
推荐文章: