Vue.js中ref的两种用法是否同源?求底层机制解析
ref Serves Two Purposes (Reactive Values & DOM References) At their core, both uses of ref share the exact same underlying mechanism: creating a trackable reference object with a value property. This is why Vue reuses the same API for both scenarios—they’re two sides of the same "reference" coin.
Core Mechanism: The RefImpl Object
Every ref (whether for reactive data or DOM elements) is an instance of Vue's internal RefImpl class. This class handles two key things:
- It wraps a value (primitive data, object, or DOM element) behind a
valuegetter/setter. - It tracks dependencies when the
valueis accessed, and triggers updates when thevalueis modified.
Breakdown of Each Use Case
1. Reactive Primitive Values (const count = ref(0))
Vue's reactive system natively tracks changes to object properties, but can’t track primitive values (strings, numbers, booleans) directly—since they’re immutable and don’t have properties to watch.
ref solves this by wrapping the primitive in an object with a value property. When you access or modify count.value, Vue’s reactivity system detects the operation:
- Accessing
count.valuecollects dependencies (like components that use this value in templates). - Modifying
count.valuetriggers updates for all collected dependencies.
2. DOM Element References (<button ref="mybutton">OK</button>)
For DOM refs, Vue leverages the same ref object structure. Here’s how it works:
- When the component mounts, Vue locates the DOM element matching the
refattribute. - It assigns that DOM element to the
valueproperty of the correspondingrefobject. - If the element is unmounted (e.g., via
v-if), Vue setsmybutton.valuetonull—and this change is tracked just like a reactive value update.
Why the Same Name?
Vue’s design prioritizes simplicity and conceptual consistency. Both uses of ref revolve around the idea of a stable, trackable reference:
- For reactive values, it’s a reference to a piece of data that can change over time.
- For DOM elements, it’s a reference to a DOM node that exists (or not) in the DOM tree.
By reusing the ref API, Vue avoids introducing separate concepts (like reactivePrimitive and domRef) that would add unnecessary complexity to the framework.
Practical Example: Combining Both Uses
You can see the shared mechanism in action by combining reactive values and DOM refs:
import { ref, watch } from 'vue' const showButton = ref(true) const myButton = ref(null) // Watch for changes to the DOM ref watch(myButton, (newEl) => { if (newEl) { console.log('Button is mounted:', newEl) newEl.textContent = 'Updated OK' } else { console.log('Button was unmounted') } }) const toggleButton = () => { showButton.value = !showButton.value }
<template> <button ref="myButton" v-if="showButton">OK</button> <button @click="toggleButton">Toggle Button</button> </template>
When you toggle the button, myButton.value switches between the DOM element and null, and the watcher triggers—just like it would for a reactive value change.
内容的提问来源于stack exchange,提问作者Sylv

