Reaktivität in Vue
Veröffentlicht: 2022-03-10In diesem Artikel werden wir uns mit der Reaktivität in Vue befassen, wie sie funktioniert und wie wir mit neu erstellten Methoden und Funktionen reaktive Variablen erstellen können. Dieser Artikel richtet sich an Entwickler, die die Funktionsweise von Vue 2.x gut verstehen und sich mit dem neuen Vue 3 vertraut machen möchten.
Wir werden eine einfache Anwendung erstellen, um dieses Thema besser zu verstehen. Den Code für diese App finden Sie auf GitHub.
Standardmäßig ist JavaScript nicht reaktiv . Das bedeutet, wenn wir die Variable boy
erstellen und in Teil A unserer Anwendung darauf verweisen und dann boy
in Teil B ändern, wird Teil A nicht mit dem neuen Wert von boy
aktualisiert.
let framework = 'Vue'; let sentence = `${framework} is awesome`; console.log(sentence) // logs "Vue is awesome" framework = 'React'; console.log(sentence) //should log "React is awesome" if 'sentence' is reactive.
Das obige Snippet ist ein perfektes Beispiel für die nicht reaktive Natur von JavaScript – weshalb sich die Änderung nicht in der sentence
widerspiegelt.
In Vue 2.x waren props
, computed
und data()
alle standardmäßig reaktiv, mit Ausnahme von Eigenschaften, die nicht in data
vorhanden sind, wenn solche Komponenten erstellt werden. Dies bedeutet, dass, wenn eine Komponente in das DOM eingefügt wird, nur die vorhandenen Eigenschaften im data
der Komponente dazu führen würden, dass die Komponente aktualisiert wird, wenn sich solche Eigenschaften ändern.
Intern verwendet Vue 3 das Proxy
-Objekt (eine ECMAScript 6-Funktion), um sicherzustellen, dass diese Eigenschaften reaktiv sind, bietet aber weiterhin die Option, Object.defineProperty
von Vue 2 für die Internet Explorer-Unterstützung (ECMAScript 5) zu verwenden. Diese Methode definiert eine neue Eigenschaft direkt für ein Objekt oder ändert eine vorhandene Eigenschaft für ein Objekt und gibt das Objekt zurück.
Auf den ersten Blick und da die meisten von uns bereits wissen, dass Reaktivität in Vue nichts Neues ist, mag es unnötig erscheinen, diese Eigenschaften zu nutzen, aber die Options-API hat ihre Grenzen, wenn Sie es mit einer großen Anwendung mit wiederverwendbaren Funktionen in mehreren zu tun haben Teile der Bewerbung. Zu diesem Zweck wurde die neue Kompositions-API eingeführt, um bei der Abstraktion von Logik zu helfen, um eine Codebasis leichter lesbar und wartungsfreundlicher zu machen. Außerdem können wir jetzt ganz einfach jede Variable reaktiv machen, unabhängig von ihrem Datentyp, indem wir eine der neuen Eigenschaften und Methoden verwenden.
Wenn wir die setup
-Option verwenden, die als Einstiegspunkt für die Kompositions-API dient, sind das data
, computed
Eigenschaften und methods
nicht zugänglich, da die Komponenteninstanz noch nicht erstellt wurde, wenn das setup
ausgeführt wird. Dies macht es unmöglich, die eingebaute Reaktivität in irgendeiner dieser Funktionen in setup
zu nutzen. In diesem Tutorial lernen wir alle Möglichkeiten kennen, wie wir dies tun können.
Die reaktive Methode
Laut Dokumentation kann die reactive
Methode, die das Äquivalent von Vue.observable()
in Vue 2.6 ist, nützlich sein, wenn wir versuchen, ein Objekt zu erstellen, dessen Eigenschaften alle reaktiv sind (wie das data
in den Options API). Unter der Haube verwendet das data
in der Options-API diese Methode, um alle darin enthaltenen Eigenschaften reaktiv zu machen.
Aber wir können unser eigenes reaktives Objekt wie folgt erstellen:
import { reactive } from 'vue' // reactive state let user = reactive({ "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "[email protected]", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" }, "cars": { "number": 0 } })
Hier haben wir die reactive
Methode aus Vue importiert und dann unsere user
deklariert, indem wir ihren Wert als Argument an diese Funktion übergeben haben. Dabei haben wir user
reaktiv gemacht, und wenn wir user
in unserem Template verwenden und sich entweder das Objekt oder eine Eigenschaft dieses Objekts ändern sollte, dann wird dieser Wert automatisch in diesem Template aktualisiert.
ref
So wie wir eine Methode haben, um Objekte reaktiv zu machen, brauchen wir auch eine, um andere eigenständige primitive Werte (Strings, boolesche Werte, undefinierte Werte, Zahlen usw.) und Arrays reaktiv zu machen. Während der Entwicklung arbeiteten wir mit diesen anderen Datentypen, mussten aber auch reaktiv sein. Der erste Ansatz, den wir uns vorstellen könnten, wäre, reactive
zu verwenden und den Wert der Variablen zu übergeben, die wir reaktiv machen möchten.
import { reactive } from 'vue' const state = reactive({ users: [], });
Da reactive
eine tiefe reaktive Konvertierung hat, wäre der user
als Eigenschaft ebenfalls reaktiv, wodurch unser Ziel erreicht würde; Daher würde der user
immer überall dort aktualisieren, wo es in der Vorlage einer solchen App verwendet wird. Aber mit der Eigenschaft ref
können wir jede Variable mit jedem Datentyp reaktiv machen, indem wir den Wert dieser Variablen an ref
übergeben. Diese Methode funktioniert auch für Objekte, verschachtelt das Objekt jedoch eine Ebene tiefer als bei Verwendung der reactive
Methode.
let property = { rooms: '4 rooms', garage: true, swimmingPool: false } let reactiveProperty = ref(property) console.log(reactiveProperty) // prints { // value: {rooms: "4 rooms", garage: true, swimmingPool: false} // }
Unter der Haube nimmt ref
dieses übergebene Argument und konvertiert es in ein Objekt mit einem Schlüssel von value
. Das heißt, wir können auf unsere Variable zugreifen, indem wir variable.value
aufrufen, und wir können auch ihren Wert ändern, indem wir sie auf die gleiche Weise aufrufen.
import {ref} from 'vue' let age = ref(1) console.log(age.value) //prints 1 age.value++ console.log(age.value) //prints 2
Damit können wir ref
in unsere Komponente importieren und eine reaktive Variable erstellen:
<template> <div class="home"> <form @click.prevent=""> <table> <tr> <th>Name</th> <th>Username</th> <th>email</th> <th>Edit Cars</th> <th>Cars</th> </tr> <tr v-for="user in users" :key="user.id"> <td>{{ user.name }}</td> <td>{{ user.username }}</td> <td>{{ user.email }}</td> <td> <input type="number" name="cars" v-model.number="user.cars.number" /> </td> <td> <cars-number :cars="user.cars" /> </td> </tr> </table> <p>Total number of cars: {{ getTotalCars }}</p> </form> </div> </template> <script> // @ is an alias to /src import carsNumber from "@/components/cars-number.vue"; import axios from "axios"; import { ref } from "vue"; export default { name: "Home", data() { return {}; }, setup() { let users = ref([]); const getUsers = async () => { let { data } = await axios({ url: "data.json", }); users.value = data; }; return { users, getUsers, }; }, components: { carsNumber, }, created() { this.getUsers(); }, computed: { getTotalCars() { let users = this.users; let totalCars = users.reduce(function(sum, elem) { return sum + elem.cars.number; }, 0); return totalCars; }, }; </script>
Hier haben wir ref
importiert, um eine reaktive users
in unserer Komponente zu erstellen. Wir haben dann axios
importiert, um Daten aus einer JSON-Datei im public
Ordner abzurufen, und wir haben unsere carsNumber
Komponente importiert, die wir später erstellen werden. Als nächstes haben wir eine reaktive users
mit der ref
-Methode erstellt, damit users
aktualisieren können, wann immer sich die Antwort aus unserer JSON-Datei ändert.
Wir haben auch eine getUser
Funktion erstellt, die das users
aus unserer JSON-Datei mit Axios abruft, und wir haben den Wert aus dieser Anfrage der users
zugewiesen. Schließlich haben wir eine berechnete Eigenschaft erstellt, die die Gesamtzahl der Autos berechnet, die unsere Benutzer haben, da wir sie im Vorlagenabschnitt geändert haben.
Es ist wichtig zu beachten, dass beim Zugriff auf ref
Eigenschaften, die im Vorlagenabschnitt oder außerhalb von setup()
zurückgegeben werden, diese automatisch flach ausgepackt werden. Das bedeutet, dass refs
, die ein Objekt sind, immer noch einen .value
benötigen, um darauf zugreifen zu können. Da es sich bei users
um ein Array handelt, könnten wir einfach users
und nicht users.value
in getTotalCars
.
Im Vorlagenabschnitt haben wir eine Tabelle angezeigt, die die Informationen jedes Benutzers zusammen mit einer <cars-number />
Komponente anzeigt. Diese Komponente akzeptiert eine cars
-Requisite, die in der Zeile jedes Benutzers als Anzahl der Autos angezeigt wird, die er hat. Dieser Wert wird immer dann aktualisiert, wenn sich der Wert von cars
im Benutzerobjekt ändert. Genau so würde das data
oder computed
Eigenschaft funktionieren, wenn wir mit der Options-API arbeiten würden.
toRefs
Wenn wir die Composition API verwenden, akzeptiert die setup
Funktion zwei Argumente: props
und context
. Diese props
werden von der Komponente an setup()
übergeben und ermöglichen den Zugriff auf die Requisiten, die die Komponente innerhalb dieser neuen API hat. Diese Methode ist besonders nützlich, da sie die Destrukturierung von Objekten ermöglicht, ohne ihre Reaktivität zu verlieren.
<template> <p>{{ cars.number }}</p> </template> <script> export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { console.log(props); // prints {gender: "female", cars: Proxy} }, }; </script> <style></style>
Um einen Wert zu verwenden, der ein Objekt von props
in der Kompositions-API ist, und gleichzeitig sicherzustellen, dass er seine Reaktivität beibehält, verwenden wir toRefs
. Diese Methode nimmt ein reaktives Objekt und wandelt es in ein einfaches Objekt um, in dem jede Eigenschaft des ursprünglichen reaktiven Objekts zu einer ref
wird. Das bedeutet, dass die cars
stützen…
cars: { number: 0 }
… würde jetzt das werden:
{ value: cars: { number: 0 }
Damit können wir cars
in jedem Teil der Setup-API verwenden und gleichzeitig ihre Reaktivität beibehalten.
setup(props) { let { cars } = toRefs(props); console.log(cars.value); // prints {number: 0} },
Wir können diese neue Variable mit der Überwachung der Kompositions-API watch
und auf diese Änderung reagieren, wie wir möchten.
setup(props) { let { cars } = toRefs(props); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }
toRef
Ein weiterer häufiger Anwendungsfall, mit dem wir konfrontiert werden könnten, ist die Übergabe eines Werts , der nicht unbedingt ein Objekt ist, sondern einer der Datentypen, die mit ref
arbeiten (Array, Zahl, String, Boolean usw.). Mit toRef
können wir eine reaktive Eigenschaft (dh ref
) aus einem reaktiven Quellobjekt erstellen. Dadurch würde sichergestellt, dass die Eigenschaft reaktiv bleibt und aktualisiert wird, wenn sich die übergeordnete Quelle ändert.
const cars = reactive({ Toyota: 1, Honda: 0 }) const NumberOfHondas = toRef(state, 'Honda') NumberOfHondas.value++ console.log(state.Honda) // 1 state.Honda++ console.log(NumberOfHondas.value) // 2
Hier haben wir mit der reactive
Methode ein reaktives Objekt mit den Eigenschaften Toyota
und Honda
erstellt. Wir haben auch toRef
verwendet, um eine reaktive Variable aus Honda
zu erstellen. Aus dem obigen Beispiel können wir sehen, dass der Wert in beiden Fällen aktualisiert wird, wenn wir Honda
entweder mit dem reaktiven cars
-Objekt oder NumberOfHondas
aktualisieren.
Diese Methode ist ähnlich und doch so verschieden von der toRefs
Methode, die wir oben behandelt haben, in dem Sinne, dass sie ihre Verbindung zu ihrer Quelle beibehält und für Strings, Arrays und Zahlen verwendet werden kann. Anders als bei toRefs
müssen wir uns zum Zeitpunkt der Erstellung keine Gedanken über die Existenz der Eigenschaft in ihrer Quelle machen, denn wenn diese Eigenschaft zum Zeitpunkt der Erstellung dieser ref
nicht vorhanden ist und stattdessen null
zurückgibt, würde sie dennoch gespeichert werden als gültige Eigenschaft, mit einer Form von watcher
, so dass, wenn sich dieser Wert ändert, diese mit ref
erstellte toRef
ebenfalls aktualisiert wird.
Wir können diese Methode auch verwenden, um eine reaktive Eigenschaft aus props
zu erstellen. Das würde so aussehen:
<template> <p>{{ cars.number }}</p> </template> <script> import { watch, toRefs, toRef } from "vue"; export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { let { cars } = toRefs(props); let gender = toRef(props, "gender"); console.log(gender.value); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }, }; </script>
Hier haben wir eine ref
erstellt, die auf der von props
erhaltenen gender
basiert. Dies ist praktisch, wenn wir zusätzliche Operationen an der Requisite einer bestimmten Komponente durchführen möchten.
Fazit
In diesem Artikel haben wir uns angesehen, wie Reaktivität in Vue funktioniert, indem wir einige der neu eingeführten Methoden und Funktionen von Vue 3 verwendet haben. Wir haben uns zunächst angesehen, was Reaktivität ist und wie Vue das Proxy
Objekt hinter den Kulissen verwendet, um dies zu erreichen. Wir haben uns auch angesehen, wie wir mit reactive
Objekten reaktive Objekte und mit ref
reaktive Eigenschaften erstellen können.
Schließlich haben wir uns angesehen, wie man reaktive Objekte in einfache Objekte umwandelt, deren Eigenschaften jeweils eine ref
sind, die auf die entsprechende Eigenschaft des ursprünglichen Objekts verweist, und wir haben gesehen, wie man eine ref
für eine Eigenschaft auf einem reaktiven Quellobjekt erstellt.
Weitere Ressourcen
- „Proxy“ (Objekt), MDN Web Docs
- „Grundlagen der Reaktivität“, Vue.js
- „Referenzen“, Vue.js
- „Lifecycle-Hook-Registrierung im
setup
“, Vue.js