Réactivité en vue
Publié: 2022-03-10Dans 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.
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