Fermer

octobre 4, 2023

Dois-je utiliser Ref ou Reactive dans Vue 3 ?


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 refet n’est probablement pas une source de confusion.

La vraie question est donc la suivante : ref ou pas ref?

  1. En cas de doute
    Je recommande de choisir par défaut ref. 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.
  2. 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 utiliser ref. Lorsque vous créez un objet ou un tableau
    reactivevous 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’à useNumbernous 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

octobre 4, 2023