Maison >interface Web >js tutoriel >Comment utiliser un objet avec v-model dans Vue

Comment utiliser un objet avec v-model dans Vue

Susan Sarandon
Susan Sarandonoriginal
2025-01-20 02:34:39352parcourir

How to use an object with v-model in Vue

Tout le monde connaît très bien la directive v-model de Vue.js, qui implémente une liaison de données bidirectionnelle entre les composants. Mais lors de l'implémentation manuelle de v-model pour un composant personnalisé, vous rencontrez généralement certains problèmes.

L'approche habituelle est la suivante :

<code class="language-javascript">const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
<template></template></code>

Veuillez noter que nous ne modifierons pas la valeur du modelValue prop à l'intérieur du composant. Au lieu de cela, nous transmettons la valeur mise à jour au composant parent via la méthode emit, et le composant parent effectue les modifications réelles. En effet : Les composants enfants ne doivent pas affecter l'état du composant parent, ce qui complique le flux de données et rend le débogage difficile.

Comme indiqué dans la documentation de Vue, les accessoires ne doivent pas être modifiés à l'intérieur des composants enfants. Si vous faites cela, Vue émettra un avertissement dans la console.

Comment va le sujet ?

Les objets et les tableaux en JavaScript sont un cas particulier car ils sont passés par référence. Cela signifie que les composants peuvent modifier directement les propriétés imbriquées des accessoires d'objet. Cependant, Vue ne prévient pas des modifications dans les propriétés des objets imbriqués (le suivi de ces modifications entraîne une pénalité de performances). Par conséquent, de telles modifications inattendues peuvent entraîner des problèmes dans votre application difficiles à détecter et à déboguer.

La plupart du temps, nous utilisons la valeur de base comme v-model. Cependant, dans certains cas, comme lors de la création d'un composant de formulaire, nous pouvons avoir besoin d'un v-model personnalisé capable de gérer des objets. Cela nous amène à une question importante :

Comment implémenter une coutume v-model pour manipuler les objets tout en évitant les pièges ci-dessus ?

Questions de discussion

Une façon consiste à utiliser une propriété calculée inscriptible ou defineModelune fonction d'assistance. Cependant, les deux solutions présentent un inconvénient majeur : elles modifient directement l’objet d’origine, ce qui va à l’encontre de l’objectif consistant à maintenir un flux de données clair.

Pour illustrer ce problème, regardons un exemple de composant « formulaire ». Ce composant est conçu pour émettre une copie mise à jour de l'objet vers le composant parent lorsque la valeur du formulaire change. Nous essaierons d’y parvenir en utilisant des propriétés calculées inscriptibles.

Dans cet exemple, la propriété calculée inscriptible modifie toujours l'objet d'origine.

<code class="language-javascript">import { computed } from 'vue';
import { cloneDeep } from 'lodash-es';

type Props = {
  modelValue: { name: string; email: string; };
};

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => ({ name: '', email: '' }),
});

const emit = defineEmits<{
  'update:modelValue': [value: Props['modelValue']];
}>();


const formData = computed({
  // 返回的getter对象仍然是可变的
  get() {
    return props.modelValue;
  },
  // 注释掉setter仍然会修改prop
  set(newValue) {
    emit('update:modelValue', cloneDeep(newValue));
  },
});</code>

Ceci ne fonctionne pas car l'objet renvoyé par le getter est toujours mutable, ce qui entraîne une modification inattendue de l'objet d'origine.

defineModel Même chose. Puisque update:modelValue n'est pas émis par le composant et que les propriétés de l'objet sont modifiées sans aucun avertissement.

Solution

La « méthode Vue » pour gérer cette situation consiste à utiliser des valeurs réactives internes pour représenter les objets et à implémenter deux observateurs :

  1. Un observateur surveille l'accessoire modelValue pour détecter les changements et met à jour la valeur interne. Cela garantit que l'état interne reflète les dernières valeurs d'accessoires transmises par le composant parent.
  2. Un observateur observe les changements dans les valeurs internes. Lorsque la valeur interne est mise à jour, elle émet une nouvelle version clonée de l'objet vers le composant parent pour éviter de modifier directement l'objet d'origine.

Pour éviter une boucle de rétroaction sans fin entre ces deux observateurs, nous devons nous assurer que les mises à jour de l'accessoire modelValue ne redéclenchent pas accidentellement l'observateur pour la valeur interne.

<code class="language-javascript">const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
<template></template></code>

Je sais ce que vous pensez : « C’est trop ! » Voyons comment nous pouvons le simplifier encore plus.

Simplifiez votre solution avec VueUse

Extraire cette logique dans une fonction composée réutilisable est un excellent moyen de simplifier le processus. Mais la bonne nouvelle est que nous n’avons même pas besoin de faire ça ! La fonction combinée useVModel dans VueUse peut nous aider à résoudre ce problème !

VueUse est une puissante bibliothèque d'utilitaires Vue, souvent appelée le « couteau suisse » des utilitaires composés. Il est entièrement modifiable en arbre, nous pouvons donc utiliser uniquement les pièces dont nous avons besoin sans nous soucier d'augmenter la taille de l'emballage.

Voici un exemple avant de refactoriser en utilisant useVModel :

<code class="language-javascript">import { computed } from 'vue';
import { cloneDeep } from 'lodash-es';

type Props = {
  modelValue: { name: string; email: string; };
};

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => ({ name: '', email: '' }),
});

const emit = defineEmits<{
  'update:modelValue': [value: Props['modelValue']];
}>();


const formData = computed({
  // 返回的getter对象仍然是可变的
  get() {
    return props.modelValue;
  },
  // 注释掉setter仍然会修改prop
  set(newValue) {
    emit('update:modelValue', cloneDeep(newValue));
  },
});</code>

Beaucoup plus simple !

C'est ça ! Nous avons exploré comment utiliser correctement les objets avec v-model dans Vue sans le modifier directement à partir des composants enfants. En utilisant des observateurs ou en tirant parti de fonctions de composition comme useVModel de VueUse, nous pouvons maintenir une gestion d'état claire et prévisible dans notre application.

Voici un lien Stackblitz avec tous les exemples de cet article. N'hésitez pas à explorer et à expérimenter.

Merci d'avoir lu et bon codage !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn