Réactivité en vue

Publié: 2022-03-10
Résumé rapide ↬ La réactivité est la capacité pour une variable (tableau, chaîne, nombre, objet, etc.) de se mettre à jour lorsque sa valeur ou toute autre variable à laquelle elle fait référence est modifiée après la déclaration.

Dans cet article, nous allons examiner la réactivité dans Vue, son fonctionnement et la manière dont nous pouvons créer des variables réactives à l'aide de méthodes et de fonctions nouvellement créées. Cet article est destiné aux développeurs qui ont une bonne compréhension du fonctionnement de Vue 2.x et qui cherchent à se familiariser avec le nouveau Vue 3.

Nous allons construire une application simple pour mieux comprendre ce sujet. Le code de cette application se trouve sur GitHub.

Par défaut, JavaScript n'est pas réactif . Cela signifie que si nous créons la variable boy et la référençons dans la partie A de notre application, puis procédons à la modification de boy dans la partie B, la partie A ne sera pas mise à jour avec la nouvelle valeur de boy .

 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.

L'extrait ci-dessus est un exemple parfait de la nature non réactive de JavaScript - par conséquent, pourquoi le changement n'est pas reflété dans la variable sentence .

Dans Vue 2.x, props , computed et data() étaient tous réactifs par défaut, à l'exception des propriétés qui ne sont pas présentes dans data lors de la création de ces composants. Cela signifie que lorsqu'un composant est injecté dans le DOM, seules les propriétés existantes dans l'objet de data du composant entraîneront la mise à jour du composant si et quand ces propriétés changent.

En interne, Vue 3 utilise l'objet Proxy (une fonctionnalité ECMAScript 6) pour s'assurer que ces propriétés sont réactives, mais il offre toujours la possibilité d'utiliser Object.defineProperty de Vue 2 pour la prise en charge d'Internet Explorer (ECMAScript 5). Cette méthode définit une nouvelle propriété directement sur un objet ou modifie une propriété existante sur un objet et renvoie l'objet.

À première vue et comme la plupart d'entre nous savent déjà que la réactivité n'est pas nouvelle dans Vue, il peut sembler inutile d'utiliser ces propriétés, mais l'API Options a ses limites lorsqu'il s'agit d'une grosse application avec des fonctions réutilisables dans plusieurs parties de la demande. À cette fin, la nouvelle API de composition a été introduite pour aider à la logique d'abstraction afin de faciliter la lecture et la maintenance d'une base de code. De plus, nous pouvons désormais facilement rendre n'importe quelle variable réactive quel que soit son type de données en utilisant l'une des nouvelles propriétés et méthodes.

Lorsque nous utilisons l'option setup , qui sert de point d'entrée pour l'API de composition, l'objet data , les propriétés computed et les methods sont inaccessibles car l'instance du composant n'a pas encore été créée lors de l'exécution setup . Cela rend impossible de tirer parti de la réactivité intégrée dans l'une de ces fonctionnalités dans setup . Dans ce didacticiel, nous allons découvrir toutes les façons dont nous pouvons le faire.

Plus après saut! Continuez à lire ci-dessous ↓

La méthode réactive

Selon la documentation, la méthode reactive , qui est l'équivalent de Vue.observable() dans Vue 2.6, peut être utile lorsque nous essayons de créer un objet dont toutes les propriétés sont réactives (comme l'objet de data dans les Options API). Sous le capot, l'objet de data de l'API Options utilise cette méthode pour rendre réactives toutes les propriétés qu'il contient.

Mais nous pouvons créer notre propre objet réactif comme ceci :

 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 } })

Ici, nous avons importé la méthode reactive de Vue, puis nous avons déclaré notre variable user en passant sa valeur à cette fonction en tant qu'argument. Ce faisant, nous avons rendu user réactif et, par conséquent, si nous utilisons user dans notre modèle et si l'objet ou une propriété de cet objet devait changer, cette valeur sera automatiquement mise à jour dans ce modèle.

ref

Tout comme nous avons une méthode pour rendre les objets réactifs, nous en avons également besoin pour rendre réactifs d' autres valeurs primitives autonomes (chaînes, booléens, valeurs indéfinies, nombres, etc.) et des tableaux. Pendant le développement, nous travaillerions avec ces autres types de données tout en ayant besoin qu'ils soient réactifs. La première approche à laquelle nous pourrions penser serait d'utiliser reactive et de transmettre la valeur de la variable que nous voulons rendre réactive.

 import { reactive } from 'vue' const state = reactive({ users: [], });

Parce que reactive a une conversion réactive profonde, user en tant que propriété serait également réactif, atteignant ainsi notre objectif ; par conséquent, user mettrait toujours à jour n'importe où il est utilisé dans le modèle d'une telle application. Mais avec la propriété ref , nous pouvons rendre réactive n'importe quelle variable avec n'importe quel type de données en passant la valeur de cette variable à ref . Cette méthode fonctionne également pour les objets, mais elle imbrique l'objet à un niveau plus profond que lorsque la méthode reactive est utilisée.

 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} // }

Sous le capot, ref prend cet argument qui lui est passé et le convertit en un objet avec une clé de value . Cela signifie que nous pouvons accéder à notre variable en appelant variable.value , et nous pouvons également modifier sa valeur en l'appelant de la même manière.

 import {ref} from 'vue' let age = ref(1) console.log(age.value) //prints 1 age.value++ console.log(age.value) //prints 2

Avec cela, nous pouvons importer ref dans notre composant et créer une variable réactive :

 <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>

Ici, nous avons importé ref afin de créer une variable d' users réactifs dans notre composant. Nous avons ensuite importé axios pour récupérer les données d'un fichier JSON dans le dossier public , et nous avons importé notre composant carsNumber , que nous créerons plus tard. La prochaine chose que nous avons faite a été de créer une variable d' users réactifs à l'aide de la méthode ref , afin que users puissent mettre à jour chaque fois que la réponse de notre fichier JSON change.

Nous avons également créé une fonction getUser qui récupère le tableau users de notre fichier JSON à l'aide d'axios, et nous avons attribué la valeur de cette requête à la variable users . Enfin, nous avons créé une propriété calculée qui calcule le nombre total de voitures que nos utilisateurs ont comme nous l'avons modifié dans la section modèle.

Il est important de noter que lors de l'accès aux propriétés ref renvoyées dans la section template ou en dehors de setup() , elles sont automatiquement désencapsulées en profondeur. Cela signifie que les refs qui sont un objet nécessiteraient toujours une .value pour être accessibles. Parce que users est un tableau, nous pourrions simplement utiliser users et non users.value dans getTotalCars .

Dans la section modèle, nous avons affiché un tableau qui affiche les informations de chaque utilisateur, ainsi qu'un composant <cars-number /> . Ce composant accepte un accessoire de cars qui s'affiche dans la ligne de chaque utilisateur en tant que nombre de voitures qu'il possède. Cette valeur est mise à jour chaque fois que la valeur de cars change dans l'objet utilisateur , ce qui correspond exactement à la façon dont l'objet data ou la propriété computed fonctionnerait si nous travaillions avec l'API Options.

toRefs

Lorsque nous utilisons l'API Composition, la fonction setup accepte deux arguments : props et context . Ce props est passé du composant à setup() , et il permet d'accéder aux props que le composant a depuis l'intérieur de cette nouvelle API. Cette méthode est particulièrement utile car elle permet de déstructurer des objets sans perdre sa réactivité.

 <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>

Pour utiliser une valeur qui est un objet de props dans l'API de composition tout en veillant à ce qu'elle conserve sa réactivité, nous utilisons toRefs . Cette méthode prend un objet réactif et le convertit en un objet simple dans lequel chaque propriété de l'objet réactif d'origine devient une ref . Cela signifie que les cars supportent…

 cars: { number: 0 }

… deviendrait maintenant ceci :

 { value: cars: { number: 0 }

Avec cela, nous pouvons utiliser des cars dans n'importe quelle partie de l'API de configuration tout en maintenant sa réactivité.

 setup(props) { let { cars } = toRefs(props); console.log(cars.value); // prints {number: 0} },

Nous pouvons surveiller cette nouvelle variable à l'aide de la watch de l'API de composition et réagir à ce changement comme nous le souhaitons.

 setup(props) { let { cars } = toRefs(props); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }

toRef

Un autre cas d'utilisation courant auquel nous pourrions être confrontés consiste à transmettre une valeur qui n'est pas nécessairement un objet mais plutôt l'un des types de données qui fonctionnent avec ref (tableau, nombre, chaîne, booléen, etc.). Avec toRef , nous pouvons créer une propriété réactive (c'est-à-dire ref ) à partir d'un objet réactif source. Cela garantirait que la propriété reste réactive et se mettrait à jour chaque fois que la source parente change.

 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

Ici, nous avons créé un objet réactif en utilisant la méthode reactive , avec les propriétés Toyota et Honda . Nous avons également utilisé toRef pour créer une variable réactive à partir de Honda . Dans l'exemple ci-dessus, nous pouvons voir que lorsque nous mettons à jour Honda à l'aide de l'objet cars réactives ou de NumberOfHondas , la valeur est mise à jour dans les deux instances.

Cette méthode est similaire et pourtant si différente de la méthode toRefs que nous avons abordée ci-dessus dans le sens où elle maintient sa connexion à sa source et peut être utilisée pour les chaînes, les tableaux et les nombres. Contrairement à toRefs , nous n'avons pas à nous soucier de l'existence de la propriété dans sa source au moment de la création, car si cette propriété n'existe pas au moment de la création de cette ref et renvoie à la place null , elle serait toujours stockée comme une propriété valide, avec une forme d' watcher mis en place, de sorte que lorsque cette valeur change, cette ref créée à l'aide toRef serait également mise à jour.

Nous pouvons également utiliser cette méthode pour créer une propriété réactive à partir de props . Cela ressemblerait à ceci :

 <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>

Ici, nous avons créé une ref qui serait basée sur la propriété gender obtenue à partir de props . Cela est pratique lorsque nous voulons effectuer des opérations supplémentaires sur la prop d'un composant particulier.

Conclusion

Dans cet article, nous avons examiné le fonctionnement de la réactivité dans Vue en utilisant certaines des méthodes et fonctions nouvellement introduites de Vue 3. Nous avons commencé par examiner ce qu'est la réactivité et comment Vue utilise l'objet Proxy dans les coulisses pour y parvenir. Nous avons également examiné comment créer des objets réactifs à l'aide de reactive et comment créer des propriétés réactives à l'aide de ref .

Enfin, nous avons vu comment convertir des objets réactifs en objets simples, dont chacune des propriétés est une ref pointant vers la propriété correspondante de l'objet d'origine, et nous avons vu comment créer une ref pour une propriété sur un objet source réactif.

Autres ressources

  • "Proxy" (objet), MDN Web Docs
  • « Fondamentaux de la réactivité », Vue.js
  • "Réfs", Vue.js
  • « setup Lifecycle Hook Registration Inside », Vue.js