跳到主要内容

官方实现

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>