官方实现
2024年03月18日
一、packages/reactivity/src/ref.ts ref()
export function ref(value?: unknown) {
return createRef(value, false)
}
二、packages/reactivity/src/ref.ts createRef
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
三、packages/reactivity/src/ref.ts RefImpl
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
trackRefValue(this)
return this._value
}
set value(newVal) {
const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}
测试用例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script type="importmap">
{
"imports": {
"vue": "../../dist/vue.runtime.esm-bundler.js"
}
}
</script>
</head>
<body>
<div id="app"></div>
<script type="module">
import { ref, onMounted, createApp } from 'vue'
const App = {
template: `<div> {{ count }}</div>`,
setup() {
const count = ref(0)
onMounted(() => {
setTimeout(() => {
count.value += 1
}, 3000)
console.log(count)
})
return {
count
}
}
}
const app = createApp(App)
app.mount('#app')
</script>
</body>
</html>