Entmystifizierung der Vue 3-Reaktivität – Ein tiefer Einblick in ref, reactive und effect
Emily Parker
Product Engineer · Leapcell

Einleitung
In der modernen Webentwicklung ist die Erstellung dynamischer und reaktionsschneller Benutzeroberflächen von größter Bedeutung. Frameworks wie Vue.js haben diesen Prozess erheblich vereinfacht und bieten leistungsstarke Werkzeuge für die effiziente Verwaltung des Anwendungszustands und die Rendering von Updates. Im Herzen der Eleganz von Vue 3 liegt sein verfeinertes Reaktivitätssystem, ein ausgeklügelter Mechanismus, der automatisch Abhängigkeiten verfolgt und Komponenten nur bei Bedarf neu rendert. Das Verständnis dieses Systems ist entscheidend für das Schreiben performanter, wartbarer und vorhersehbarer Vue-Anwendungen. Dieser Artikel wird die zugrunde liegenden Prinzipien der Reaktivität von Vue 3 gründlich untersuchen und sich auf die grundlegenden Bausteine konzentrieren: ref
, reactive
und effect
.
Kernkonzepte der Reaktivität
Bevor wir uns mit den spezifischen APIs befassen, wollen wir ein grundlegendes Verständnis der Schlüsselkonzepte aufbauen, die das Reaktivitätssystem von Vue 3 untermauern.
Reaktiver Zustand: Dies bezieht sich auf Daten, die bei Änderungen potenziell eine Aktualisierung der Benutzeroberfläche auslösen sollen. In Vue deklarieren Sie bestimmte Daten explizit als reaktiv.
Abhängigkeitsverfolgung: Die Fähigkeit des Systems, zu „wissen“, welche Teile Ihres Codes (z. B. Vorlagen-Renderings, berechnete Eigenschaften) von bestimmten reaktiven Zustandsstücken abhängen.
Änderungserkennung: Der Mechanismus, der Änderungen am reaktiven Zustand überwacht.
Nebeneffekt (oder Effekt): Jede Operation, die reaktiven Zustand liest und bei Zustandsänderungen möglicherweise neu ausgeführt werden muss. Der häufigste Effekt ist das Rendern der Vorlage der Komponente.
Mit diesen Konzepten im Hinterkopf wollen wir untersuchen, wie ref
und reactive
reaktiven Zustand erstellen und wie effect
die Updates orchestriert.
Erstellung von reaktivem Zustand
Vue 3 bietet zwei primäre Möglichkeiten, reaktiven Zustand zu deklarieren: ref
und reactive
. Ihre Wahl hängt oft von der Art der Daten ab, mit denen Sie es zu tun haben.
ref
für primitive Werte
ref
wird hauptsächlich zum Erstellen reaktiver Referenzen auf primitive Werte wie Zahlen, Zeichenketten und Booleans oder sogar einzelne Objekte verwendet. Es umschließt den Wert in einem Objekt mit einer .value
-Eigenschaft. Dieser Wrapper ermöglicht es dem Reaktivitätssystem, Änderungen am zugrunde liegenden Primitiv zu verfolgen.
import { ref } from 'vue'; // Erstellen einer reaktiven Zahl const count = ref(0); console.log(count.value); // 0 // Modifizieren der reaktiven Zahl count.value++; console.log(count.value); // 1 // Beispiel in einer Vue-Komponente // <template> // <p>Count: {{ count }}</p> // <button @click="count++">Increment</button> // </template> // <script setup> // import { ref } from 'vue'; // const count = ref(0); // </script>
Wenn auf count.value
in einer Vorlage oder einem effect
zugegriffen wird, registriert das Reaktivitätssystem von Vue eine Abhängigkeit. Wenn auf count.value
anschließend zugegriffen wird, „benachrichtigt“ das System alle registrierten Abhängigkeiten und löst deren erneute Ausführung aus.
reactive
für Objekte und Arrays
reactive
wird zum Erstellen reaktiver Objekte und Arrays verwendet. Es konvertiert ein gewöhnliches JavaScript-Objekt in einen reaktiven Proxy. Jede verschachtelte Eigenschaft innerhalb dieses Objekts oder jedes Element im Array wird ebenfalls reaktiv.
import { reactive } from 'vue'; // Erstellen eines reaktiven Objekts const user = reactive({ name: 'Alice', age: 30, address: { street: '123 Main St', city: 'Anytown' } }); console.log(user.name); // Alice // Modifizieren einer Eigenschaft user.age++; console.log(user.age); // 31 // Modifizieren einer verschachtelten Eigenschaft user.address.city = 'Newcity'; console.log(user.address.city); // Newcity // Beispiel in einer Vue-Komponente // <template> // <p>Name: {{ user.name }}</p> // <p>City: {{ user.address.city }}</p> // <button @click="user.age++">Grow Older</button> // </template> // <script setup> // import { reactive } from 'vue'; // const user = reactive({ // name: 'Bob', // age: 25, // address: { city: 'Oldcity' } // }); // </script>
reactive
verwendet intern das Proxy
-Objekt von JavaScript. Wenn Sie auf eine Eigenschaft eines reaktiven Objekts zugreifen oder diese ändern, fängt der Proxy
diese Operationen ab. Dies ermöglicht es Vue, die Abhängigkeitsverfolgung durchzuführen (wenn eine Eigenschaft gelesen wird) und Updates auszulösen (wenn eine Eigenschaft geschrieben wird).
Die Beziehung zwischen ref
und reactive
Es ist üblich, ref
auch für Objekte in der setup
-Funktion zu verwenden, wenn sie als eigenständiges reaktives Zustandsstück gedacht sind. Wenn ein ref
ein Objekt enthält, macht Vue dieses Objekt automatisch intern mit reactive
reaktiv. Daher ist ref({ data: 'value' })
funktional ähnlich wie reactive({ data: 'value' })
, aber das erstere erfordert immer noch den Zugriff über .value
.
Während reactive
das reaktive Objekt direkt verfügbar macht, bietet ref
eine konsistente Oberfläche (.value
) sowohl für Primitivwerte als auch für Objekte, was einige Muster vereinfachen kann, insbesondere wenn reaktive Werte weitergegeben werden.
Der Orchestrator effect
Der Kern dessen, wie Reaktivität tatsächlich „etwas tut“, ist die effect
-Funktion. Sie wird normalerweise nicht direkt für die Anwendungsentwicklung freigegeben (es sei denn, Sie entwickeln eine Bibliothek oder tauchen tief in die Reaktivität ein), aber ihr Verständnis ist für den zugrunde liegenden Mechanismus von entscheidender Bedeutung. effect
nimmt eine Funktion als Argument entgegen, und diese Funktion wird sofort ausgeführt und immer dann erneut ausgeführt, wenn einer der reaktiven Abhängigkeiten, auf die innerhalb dieses Aufrufs zugegriffen wird, sich ändern.
Der Rendering-Mechanismus von Vue (Vorlagenkompilierung) erstellt implizit einen effect
. Wenn Sie die <template>
einer Komponente definieren, kompiliert Vue sie in eine Rendefunktion. Diese Rendefunktion wird zu einem effect
. Wenn count.value
in der Vorlage gelesen wird, registriert Vue count
als Abhängigkeit. Wenn sich count.value
ändert, wird der effect
(die Rendefunktion) erneut ausgeführt, was dazu führt, dass die Komponente neu gerendert wird.
Lassen Sie uns eine vereinfachte Version veranschaulichen, wie effect
dies ermöglicht:
// Dies ist eine konzeptionelle Darstellung, kein direkt ausführbarer Vue-Code // Stellen Sie sich einen vereinfachten Reaktivitätskern vor let activeEffect = null; const targetMap = new WeakMap(); // Ordnet Zielobjekte Maps von Props zu Sets von Effekten zu function track(target, key) { if (activeEffect) { let depsMap = targetMap.get(target); if (!depsMap) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())); } dep.add(activeEffect); } } function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) return; const dep = depsMap.get(key); if (dep) { dep.forEach(effect => effect()); } } // Vereinfachte ref-Implementierung function ref(raw) { const r = { get value() { track(r, 'value'); return raw; }, set value(newVal) { raw = newVal; trigger(r, 'value'); } }; return r; } // Vereinfachte reactive (Proxy) Implementierung function reactive(obj) { return new Proxy(obj, { get(target, key, receiver) { track(target, key); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); trigger(target, key); return result; } }); } function effect(fn) { const effectFn = () => { activeEffect = effectFn; // Setzt den aktuellen aktiven Effekt try { return fn(); // Führt die Funktion aus und löst Tracks aus } finally { activeEffect = null; // Löscht den aktiven Effekt } }; effectFn(); // Sofortige Ausführung return effectFn; // Rückgabe für manuelles Stoppen (falls erforderlich) } // --- Anwendungsbeispiel --- const myCount = ref(0); const myUser = reactive({ name: 'Bob' }); effect(() => { console.log(`Count changed: ${myCount.value}`); }); effect(() => { console.log(`User name changed: ${myUser.name}`); }); myCount.value++; // Löst "Count changed: 1" aus myUser.name = 'Alice'; // Löst "User name changed: Alice" aus
In diesem vereinfachten Modell:
- Wenn
effect
aufgerufen wird, wirdactiveEffect
auf die aktuelle Funktion gesetzt. - Innerhalb der Funktion wird beim Zugriff auf
myCount.value
derget
-Handler dessentrack
aufruft. track
verwendetactiveEffect
, um die aktuelleeffect
-Funktion als Abhängigkeit fürmyCount
(speziell seine 'value'-Eigenschaft) zu registrieren.- Ebenso ruft beim Zugriff auf
myUser.name
dessenget
-Handler (vonProxy
)track
auf, der deneffect
als Abhängigkeit fürmyUser
(speziell seine 'name'-Eigenschaft) registriert. - Beim Aktualisieren von
myCount.value
ruft dessenset
-Handlertrigger
auf. trigger
sucht alle für die 'value'-Eigenschaft vonmyCount
registrierten Effekte und führt sie erneut aus.- Dieselbe Logik gilt für
myUser.name
, wenn es aktualisiert wird.
Dieses ständige Zusammenspiel von track
und trigger
in ref
s und reactive
-Proxies, orchestriert vom effect
-Runner, bildet das Rückgrat des hocheffizienten und automatischen Reaktivitätssystems von Vue.
Fazit
Das Reaktivitätssystem von Vue 3, das auf ref
, reactive
und dem zugrunde liegenden effect
-Mechanismus aufbaut, bietet eine leistungsstarke und intuitive Möglichkeit, den Anwendungszustand zu verwalten und die UI-Konsistenz sicherzustellen. Durch die Nutzung von ref
für primitive Werte und reactive
für Objekte und Arrays können Entwickler reaktiven Zustand deklarieren, der automatisch Updates für alle abhängigen Effekte, einschließlich Komponentrenderings, auslöst. Dieser deklarative Ansatz vereinfacht die komplexe Zustandsverwaltung erheblich und macht Vue-Anwendungen vorhersehbarer und einfacher zu warten. Die Eleganz dieses Systems liegt in seiner Fähigkeit, Abhängigkeiten automatisch zu verfolgen und Updates präzise zu lokalisieren, was zu hochoptimierten und performanten Benutzeroberflächen führt.