190 votes

réf vs réactif dans Vue 3?

En regardant quelques exemples de tutoriels de prévisualisation de personnes pour Vue 3. [Actuellement en version bêta]

J'ai trouvé deux exemples :

Reactive

import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}

Ref

import { ref, computed, onMounted } from "vue";

export default {
  setup(props) {
    // State
    const money = ref(1);
    const delta = ref(1);

    // Refs
    const titleRef = ref(null);

    // Computed props
    const formattedMoney = computed(() => money.value.toFixed(2));

    // Hooks
    onMounted(() => {
      console.log("titleRef", titleRef.value);
    });

    // Methods
    const add = () => (money.value += Number(delta.value));

    return {
      delta,
      money,
      titleRef,
      formattedMoney,
      add
    };
  }
};

376voto

Chris Hayes Points 1575

Points clés

  • reactive() ne prend que des objets, PAS des primitives JS (String, Boolean, Number, BigInt, Symbol, null, undefined)
  • ref() appelle reactive() en interne
  • Étant donné que reactive() fonctionne pour les objets et que ref() appelle reactive(), les objets fonctionnent pour les deux
  • MAIS, ref() a une propriété .value pour la réaffectation, reactive() n'a pas cela et ne peut donc pas être réaffecté

Utilisation

ref() lorsque..

  • il s'agit d'une primitive (par exemple 'string', true, 23, etc)
  • il s'agit d'un objet que vous devez réaffecter ultérieurement (comme un tableau - plus d'informations ici)

reactive() lorsque..

  • il s'agit d'un objet que vous n'avez pas besoin de réaffecter, et vous souhaitez éviter les frais généraux de ref()

En Résumé

ref() semble être la solution idéale car il prend en charge tous les types d'objets et permet la réaffectation avec .value. ref() est un bon point de départ, mais une fois que vous vous familiarisez avec l'API, sachez que reactive() a moins de frais généraux, et vous pourriez le trouver mieux adapté à vos besoins.

Cas d'utilisation de ref()

Vous utiliserez toujours ref() pour les primitives, mais ref() est bon pour les objets qui doivent être réaffectés, comme un tableau.

setup() {
    const blogPosts = ref([]);
    return { blogPosts };
}
getBlogPosts() {
    this.blogPosts.value = await fetchBlogPosts();
}

Avec reactive(), il faudrait réaffecter une propriété au lieu de l'ensemble de l'objet.

setup() {
    const blog = reactive({ posts: [] });
    return { blog };
}
getBlogPosts() {
    this.blog.posts = await fetchBlogPosts();
}

Cas d'utilisation de reactive()

Un bon cas d'utilisation de reactive() est un groupe de primitives qui appartiennent ensemble:

const person = reactive({
  name: 'Albert',
  age: 30,
  isNinja: true,
});

le code ci-dessus semble plus logique que

const name = ref('Albert');
const age = ref(30);
const isNinja = ref(true);

Liens Utiles

Si vous êtes toujours perdu, ce guide simple m'a aidé: https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/

Un argument en faveur de n'utiliser que jamais ref(): https://dev.to/ycmjason/thought-on-vue-3-composition-api-reactive-considered-harmful-j8c

Les raisons pour lesquelles reactive() et ref() existent telles qu'elles le font et d'autres informations importantes, la RFC de l'API de Composition Vue: https://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api

3 votes

v3.vuejs.org/guide/… quelle est la différence entre const list = reactive([1, 2, 3]) et const divs = ref([]) ?

2 votes

@Yiping bon point. Un tableau est un objet, et les deux acceptent les objets, donc je n'étais pas sûr. Mais, il s'avère qu'il y a des avantages à réassigner des tableaux avec ref's .valeur que reactive n'a pas. github.com/vuejs/docs-next/issues/801#issuecomment-757587022

0 votes

J'ai mis à jour la réponse avec plus d'informations et d'exemples.

25voto

Denis Tsoi Points 1878

Il y a quelques similitudes entre ref et reactive, en ce sens qu'ils fournissent tous deux une méthode pour stocker des données et permettent à ces données d'être réactives.

Cependant:

Différences de haut niveau:

Vous ne pouvez pas utiliser reactive() sur des primitives (chaînes de caractères, nombres, booléens) - c'est pour cela que vous avez besoin de refs, parce que vous aurez des situations où vous aurez besoin d'avoir un "booléen réactif", par exemple...

bien sûr, vous pouvez créer un objet qui enveloppe la valeur primitive et la rendre réactive():

const wrappedBoolean = reactive({
  value: true
})

et comme ça, vous avez réinventé un ref.

Source: Discussion sur le forum Vue

Réactif

reactive prend l'objet et renvoie un proxy réactif vers l'objet d'origine.

Exemple

import {ref, reactive} from "vue";

export default {
  name: "component",
  setup() {
    const title = ref("mon super titre")
    const page = reactive({
      contenu: "meh?",
      nombre: 1,
      annonces: [{ source: "google" }],
      annoncesFiltrées: computed(() => {
        return ads.filter(ad => ad.source === "google")
      })
    })

    return {
       page, 
       title
    }
  }
}

Explication

Dans l'exemple ci-dessus, chaque fois que nous voulons modifier ou accéder aux propriétés de page,
disons page.annonces, page.annoncesFiltrées se mettront à jour via les Proxies.

1 votes

Y a-t-il un avis sur ce qui est le mieux pour les tableaux? C'est-à-dire, ref([]) vs. reactive([])?

0 votes

A posté un commentaire sur votre Q

16voto

roli roli Points 2157

Je vais simplement expliquer pourquoi il existe 2 façons de créer un état réactif :

D'autres réponses montrent déjà les différences entre les deux


reactive : Crée un état réactif. Renvoie un proxy réactif de l'objet :

import { reactive } from 'vue'

const reactiveObj = reactive({ count: 0 })
reactiveObj.count++

Avec l'API Options, nous avions l'habitude de conserver l'état réactif dans data(). Avec l'API Composition, nous pouvons obtenir le même résultat avec l'API reactive. Jusque-là, tout va bien, mais...

Pourquoi avons-nous besoin de ref ???

Tout simplement parce que reactive a des limitations telles que :

  • Perte de réactivité :

    const state = reactive({ count: 0 })

    // la fonction reçoit un nombre simple et // ne pourra pas suivre les changements de state.count callSomeFunction(state.count)

    const state = reactive({ count: 0 }) let { count } = state // n'affecte pas l'état d'origine count++

    let state = reactive({ count: 0 })

    // cela ne fonctionnera pas ! state = reactive({ count: 1 })

  • Il ne peut pas contenir des types primitifs tels que string, number ou boolean.

Ainsi, ref, a été fourni par Vue pour pallier les limitations de reactive.

ref() prend l'argument et le renvoie encapsulé dans un objet ref avec une propriété .value :

const count = ref(0)

console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

Les Refs peuvent :

  • contenir n'importe quel type de valeur

  • remplacer réactivement l'objet entier :

    const objectRef = ref({ count: 0 })

    // cela fonctionne de manière réactive objectRef.value = { count: 1 }

  • être passés dans des fonctions ou déstructurés à partir d'objets simples sans perdre la réactivité

    const obj = { foo: ref(1), bar: ref(2) }

    // la fonction reçoit un ref // elle doit accéder à la valeur via .value mais elle // conservera la connexion réactive callSomeFunction(obj.foo)

    // toujours réactif const { foo, bar } = obj


Devrais-je toujours utiliser ref ?

Opinion personnelle à suivre

La plupart des développeurs qui ont essayé les deux, suggèrent d'utiliser ref d'après les articles que j'ai lus.

Mais personnellement, je pense que ref a les mêmes limitations que reactive s'il n'est pas utilisé correctement et vous pouvez facilement tomber dans des problèmes de "Perte de réactivité". ref a également quelques comportements comme :

  • le déballage dans les templates mais cela se produit uniquement pour les propriétés de premier niveau
  • le déballage à l'intérieur de reactive
  • aucun déballage n'est effectué lorsque le ref est accédé à partir d'un tableau ou d'un type de collection natif comme Map
  • Synchronisation des refs

Aussi, devoir traiter avec .value à chaque fois est un peu déroutant, Vue le sait et il y a un RFC - Réactivité Transform à l'heure où j'écris ceci qui vise à fournir une solution.

J'espère que vous avez maintenant une meilleure compréhension de reactive et ref mais je pense qu'il est utile de mentionner qu'il y a plus d'API pour l'état réactif dont vous devriez être conscient : readonly, shallowRef, shallowReactive, shallowReadonly, unref, et bien d'autres encore.

3voto

Ref / reactive sont tous deux utilisés pour créer un objet réactif où les changements sont suivis.

Réf :

Il prend un argument primitif et retourne un objet mutable réactif. L'objet a une seule propriété 'value' et elle pointera vers l'argument pris par celui-ci.

Réactif :

Il prend un objet JavaScript comme argument et retourne une copie réactive basée sur Proxy de l'objet.

Réf vs Réactif :

Typiquement, ref et reactive sont tous deux utilisés pour créer des objets réactifs où ref est utilisé pour rendre les valeurs primitives réactives (Booléen, Nombre, Chaîne de caractères). Mais reactive ne fonctionnera pas avec les primitives mais fonctionnera pour les objets.

Pour plus de détails : Référez-vous à Réf vs Réactif

1voto

elvonkh Points 37

Vous pouvez voir ci-dessous notre exemple utilisant les références réactives dans la partie supérieure, et ci-dessous une autre syntaxe réactive alternative.

// réactivité avec la syntaxe ref

import { ref, computed } from vue

export default {
  setup() {
    const capacity = ref(4)
    const members = ref(["Tim", "John", "Andr"])
    const simpleComputed = computed(() => {
      return capacity.value - members.value.length
    })

    return { capacity, members, simpleComputed }
  }
}

// réactivité avec la syntaxe réactive

import { reactive, computed } from vue

export default {
  setup() {
    const event = reactive({
      capacity: 4,
      members: ["Tim", "John", "Andr"]
      simpleComputed: computed(() => {
        return event.capacity - event.capacity.length
      }
    })
    return { event }
  }
}

Comme le montre le code ci-dessus dans la partie inférieure, j'ai créé une nouvelle constante event qui prend un objet JavaScript simple et renvoie un objet réactif. Cela peut vous rappeler l'utilisation de l'option data dans notre syntaxe de composant régulière, où j'envoie aussi un objet. Cependant, comme vous pouvez le voir ci-dessus, je peux également inclure nos propriétés calculées dans cet objet. Vous devriez également remarquer que lorsque j'utilise cette syntaxe, nous n'avons plus besoin d'écrire .value lors de l'accès aux propriétés. Cela est dû au fait que j'accède simplement aux propriétés de l'objet event. Vous devriez également remarquer que nous retournons l'intégralité de l'événement

Les deux syntaxes sont valides pour une utilisation, et aucune n'est considérée comme étant la meilleure pratique

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X