Référer ou ne pas réfuter ? Explorons à travers une approche rapide et basée sur des exemples pour comprendre les principales différences entre ref et reactive dans Vue 3.
Cela fait un moment que Vue 3 n’a pas été entièrement publié, mais un concept qui déconcerte encore les nouveaux arrivants dans le framework est de comprendre les principales différences entre ref
et reactive
lorsque vous travaillez avec l’API de composition.
Je ne veux pas faire une réécriture complète de la documentation, alors éliminons d’abord la différence la plus « évidente », ou la différence clé que tout le monde doit absolument comprendre avant de travailler avec ces deux-là.
D’une part, reactive
ne peut fonctionner qu’avec des types d’objets. C’est Object
, Array
, Map
et Set
. Le plus flexible ref
peut fonctionner avec tout autre type de valeur, y compris des primitives comme String
et Number
. Ainsi, la première chose que vous devez vous demander lorsque vous choisissez de travailler avec l’un ou l’autre est de savoir quel type de données allez-vous rendre réactives.
Cela dit, je ne parlerai pas d’autre chose que des valeurs de type d’objet pour le reste de l’article, puisque tout ce qui n’entre pas dans cette catégorie ne peut être géré qu’en utilisant un ref
et n’est probablement pas une source de confusion.
La vraie question est donc la suivante : ref
ou pas ref
?
- En cas de doute
Je recommande de choisir par défautref
. Il est de loin plus facile de ne pas créer accidentellement un bug difficile à suivre. Mais à mesure que vous comprenez mieux oùreactive
peut mieux vous servir, vous serez en mesure de choisir le meilleur outil pour le travail. - Quand le pointeur changera
Si vous comptez travailler avec une variable réactive qui changera les pointeurs vers de nouveaux objets différents, alors vous souhaitez utiliserref
. Lorsque vous créez un objet ou un tableau
reactive
vous allez vous engager sur ce pointeur et ne pas essayer de le remplacer plus tard par un tout nouveau.
Parfois, j’ai entendu des gens dire qu’ils étaient plus à l’aise de travailler avec ref
exclusivement parce qu’ils ont seulement j’ai travaillé avec et je n’ai jamais eu à travailler avec reactive
objets avant. Dans une certaine mesure, cela peut être vrai : vous pouvez certainement vous en sortir en faisant de tout un ref
. Mais j’ai des nouvelles pour vous, si vous avez travaillé avec props
auparavant, dans l’API de composition, vous avez déjà travaillé avec reactive
objets.
setup (props) {
// props is `reactive`
}
<script setup>
const props = defineProps({})
// props is `reactive`
</script>
Dans cette optique, vous pourrez constater le principal avantage de travailler avec reactive
objets : vous n’êtes pas obligé d’utiliser le .value
property pour accéder aux valeurs de leurs propriétés.
<script setup>
import { reactive } from 'vue'
const props = defineProps({
modelValue: { type: String, default: 'Reactive prop!' }
})
console.log(props.modelValue) // outputs: Reactive prop!
const reactiveUser = reactive({
name: 'Michael Scott'
})
console.log(reactiveObj.name) // outputs: Michael Scott
</script>
Cependant, comme je l’ai mentionné plus tôt, vous devriez pas attribuer un nouvel objet ou un pointeur à la valeur réactive. Faire cela « fonctionnera » apparemment mais rompra la connectivité réactive avec l’objet d’origine, ce qui est une façon sophistiquée de dire que la réactivité liée à l’objet d’origine sera interrompue ou supprimée.
Regardons un exemple de la façon dont pas pour le faire.
<script setup>
import { reactive, toRefs, isRef, isReactive, unref, computed, ref } from 'vue'
let user = reactive({
name: 'Michael Scott'
})
const firstName = computed(() => user.name.split(' ')[0])
console.log(user.name) // outputs: Michael Scott
console.log(firstName.value) // outputs: Michael
user = reactive({
name: 'Jim Halpert'
})
console.log(user.name) // outputs: Jim Halpert
console.log(firstName.value) // outputs: Michael. BUG!
</script>
Notez que le firstName
calculé n’a pas « vu » le changement car la valeur réactive à l’intérieur firstName
est lié à l’utilisateur d’origine, Michael (ou plutôt à son pointeur).
Si vous souhaitez changer d’objet tout en gardant la réactivité dans une variable singulière, le moyen le plus sûr de le faire est d’utiliser ref
.
<script setup>
import { ref, computed } from 'vue'
const user = ref({
name: 'Michael Scott'
})
const firstName = computed(() => user.value.name.split(' ')[0])
console.log(user.value.name) // outputs: Michael Scott
console.log(firstName.value) // outputs: Michael
user.value = {
name: 'Jim Halpert'
}
console.log(user.value.name) // outputs: Jim Halpert
console.log(firstName.value) // outputs: Jim
</script>
Il est important de souligner que la vraie valeur de l’exemple ci-dessus est que même si nous avons complètement échangé l’objet utilisateur d’un point à un autre (Michael à Jim), notre firstName
la propriété calculée « verra » correctement et réagira au changement et recalculera la valeur.
Le dernier piège que je souhaite explorer est la perte de réactivité lors de l’utilisation reactive
et transmettre des valeurs aux fonctions de composition et aux bibliothèques tierces. L’exemple suivant illustre un problème courant.
<script>
#useNumber.js
import { computed } from 'vue'
export default (number) => {
const double = computed(() => number * 2)
return { double }
}
</script>
<script setup>
#MyComponent.vue
import { ref, reactive } from 'vue'
import useNumber from 'useNumber'
const reactiveObj = reactive({
myNumber: 1
})
const { double } = useNumber(reactiveObj.myNumber)
console.log(double) // Prints 2
reactiveObj.myNumber = 2
console.log(double) // Prints 2, computed did not trigger
</script>
Pouvez-vous dire exactement ce qui n’a pas fonctionné ?
Chaque fois que nous accédons à un reactive
objet ou tableau par l’une de ses propriétés ou index, on obtient le actuel valeur de l’objet réactif dans un non réactive formulaire. Ainsi, dans l’exemple ci-dessus, lorsque nous avons passé reactiveObj.myNumber
jusqu’à useNumber
nous lui avons en fait donné le Number
2, pas le pointeur réactif vers le myNumber
propriété.
Il existe plusieurs façons de résoudre ce problème. Celui que je préfère (car il fonctionne aussi très bien avec props
) est d’utiliser toRefs
.
toRefs
nous permet de créer un ref
sur chaque propriété d’un objet réactif. De cette façon, nous pouvons transmettre la valeur réactive à notre useNumber
fonction de composition.
<script>
#useNumber.js
import { computed } from 'vue'
export default (number) => {
const double = computed(() => number.value * 2) // We need .value now that its a ref
return { double }
}
</script>
<script setup>
#MyComponent.vue
import { ref, reactive, toRefs } from 'vue'
import useNumber from 'useNumber'
const reactiveObj = reactive({
myNumber: 1
})
const { myNumber } = toRefs(reactiveObj) // myNumber is a ref
const { double } = useNumber(myNumber)
console.log(double) // Prints 2
reactiveObj.myNumber = 2
// We could also do myNumber.value = 2
console.log(double) // Prints 4
</script>
J’espère qu’avec ces exemples, vous aurez acquis un peu plus de clarté sur les différences entre les deux et serez en mesure de choisir le meilleur outil pour le travail sur votre propre code !
Source link