Vue: est-ce que vuejs2.0 doit conserver l'api d'événement $broadcast, $dispatch ? Pas de bonne solution pour aborder la communication parent-enfant point à point en 2.0

Créé le 1 sept. 2016  ·  41Commentaires  ·  Source: vuejs/vue

@yyx990803 ,
Bonjour, l'équipe principale de vuejs,
J'ai du mal à trouver une bonne solution pour la communication point à point entre les composants parent-enfant avec vuejs2.0.
Étant donné que vuejs2.0 a déprécié l'api $broadcast,$dispatch, il m'est très difficile de trouver une solution alternative que $broadcast,$dispatch fournit avec la fonction de bus d'événements vuejs2.0.
J'ai écrit un fil dans le forum à ce sujet ici , et j'aimerais le coller ici pour plus de discussion.

VEUILLEZ NE PAS LE FERMER SAUF si vous avez une bonne idée ou une solution sur vuejs2.0.

<pcom id=1>
    <soncoma></soncoma>
    <soncomb></soncomb>
</pcom>
<pcom id=2>
    <soncoma></soncoma>
    <soncomb></soncomb>
</pcom>

Dans le code ci-dessus, lorsque l'enfant de pcom1, par exemple, soncoma $ emit un événement, disons,

bus.$emit('son-coma-event',somedata)

sur le pcom, nous écoutons cet événement avec

bus.$on('son-coma-event',function(){})

Je veux seulement que pcom1 gère cet événement, mais malheureusement, pcom2 le gérera également.
Comment faire face à cette condition ?

L'une des solutions de contournement dans mon application consiste à utiliser this.$parent comme bus d'événements
Chez l'enfant :

this.$parent.$emit('some-event',someData)

En parent :

{
   created(){
       this.$on('some-event',function(){})
}

Le point négatif de la solution de contournement ci-dessus est :

  1. on se couple beaucoup sur la relation parent-enfant ;
  2. cela ne fonctionne pas s'il existe un niveau plus approfondi des niveaux parent-enfant ;

Dans certaines conditions plus complexes, il sera plus difficile de trouver une bonne solution pour le système d'événement personnalisé, par exemple, un composant récursif

 <pcom>
    <recursivechild>
             <recursivechild>
                          <recursivechild>
                          </recursivechild>
             </recursivechild>
    <recursivechild>
</pcom>

 <pcom>
    <recursivechild>
             <recursivechild>
                          <recursivechild>
                          </recursivechild>
             </recursivechild>
    <recursivechild>
</pcom>

comment recursivechild communique avec son composant pcom direct ?
Veuillez donner votre idée ou point sur ces sujets.
Merci ~ !

discussion

Commentaire le plus utile

@rhyek Je voudrais donner mon 2ct sur quelques points que vous avez soulevés. Étant donné que la discussion a déjà abordé un certain nombre de sujets, j'aimerais revenir à l'essentiel sur les raisons pour lesquelles nous avons déprécié $diospatch et $broacast :

1. couplage implicite.

Si vous avez un parent et un enfant profondément imbriqué qui distribue un événement, il n'y a aucun moyen de déduire cette relation à partir du code (et il en va de même pour $broadcast , évidemment.)

Si vous regardez les autres modifications et dépréciations que nous avons introduites avec Vue 2.0, vous vous rendrez peut-être compte que la suppression du comportement implicite en faveur d'alternatives explicites est un thème commun, et la dépréciation de $dispatch adapte parfaitement.

Exemple:

// parent
events: {
  'some-event': function () { ... }
}

// deeply nested child:
$dispatch('some-event')

C'est bien lorsque le parent n'a qu'un seul enfant direct - mais dans ce cas, $emit() avec un écouteur dans le modèle n'est pas non plus un vrai travail supplémentaire.

Il devient difficile de suivre (surtout en équipe) dès que vous avez des enfants imbriqués (surtout profondément imbriqués), ou même plus d'un enfant direct - vous devez soit parcourir tous les enfants, soit vous fier aux commentaires du code pour documenter quel événement est déclenché à partir de quel composant enfant - qui est également un passe-partout supplémentaire.

Vous dites que vous aimez $dispatch et $broadcast parce que vous n'avez pas à les faire passer par d'autres composants. Et je peux convenir que c'est plus facile - mais nous n'avons pas rencontré beaucoup de situations où cela était réellement nécessaire, ou plutôt : s'il y avait une telle chaîne de transmission d'un événement, ce serait plutôt le cas que les données seraient modifiées/ en annexe/ pendant ce voyage par composante intermédiaire.

2. Noms des événements

lorsque vous utilisez $dispatch avec des composants profondément imbriqués, vous devez être très explicite dans l'espacement des noms de vos événements, car sinon, ils pourraient entrer en conflit :

// parent
events: {
  'close': function () { ... }
}

// deeply nested child 1:
$dispatch('close')
// deeply nested child 2:
$dispatch('close')

..et si ces enfants sont des bibliothèques tierces, vous êtes foutu maintenant. ou devez attraper l'événement dans un composant au milieu juste pour le renommer avant de $dispatch() plus loin jusqu'au parent. Et n'oubliez pas de commenter cela, car quelqu'un qui regarde ce code pourrait penser pourquoi vous ne faites rien d'autre avec un événement que de le renommer.

L'utilisation de $emit et de modèles d'écoute n'a pas ce problème. vous pouvez utiliser des noms d'événement simples et courts partout, ils n'entreront pas en conflit car chaque événement a son propre rappel attaché dans le modèle @close="callback ".

Je souhaite vraiment que vous n'ayez pas supprimé le *choix* d'utiliser l'un ou l'autre paradigme,

Si nous pensions que les deux paradigmes peuvent fonctionner aussi bien, nous les traiterions de la même manière. Mais nous ne le pensons pas, pour les raisons ci-dessus et plus encore.

Par conséquent, nous essayons d'orienter les utilisateurs vers les stratégies que nous avons trouvées les plus efficaces, tout en laissant un moyen de les contourner avec la méthode du "Bus global".

J'aimerais également parler de vos inquiétudes concernant l'état mondial, mais je ne suis pas sûr de bien comprendre votre position pour le moment.

Peut-être pouvez-vous fournir un exemple où vous pensez que $dispatch et $broadcast fonctionnent le mieux pour vous, et j'essaie de vous montrer comment "notre" approche pourrait améliorer la situation ?

Tous les 41 commentaires

Parce qu'il s'agit d'une discussion de proposition générale, je n'ai pas encore créé de violon. Si c'est nécessaire, j'aimerais créer pour démontrer.
merci ~ !

Cela a déjà été justifié sur les changements 2.0

Voici une copie :

Comment gérer la dépréciation de $dispatch et $broadcast ?

La raison pour laquelle nous déprécions $dispatch et $broadcast est que les flux d'événements qui dépendent de la structure arborescente des composants peuvent être difficiles à raisonner sur le moment où l'arbre des composants devient grand (en termes simples : il ne s'adapte bien dans les grandes applications et nous ne voulons pas vous mettre en difficulté plus tard). $dispatch et $broadcast ne résolvent pas non plus la communication entre les composants frères. Au lieu de cela, vous pouvez utiliser un modèle similaire à EventEmitter dans Node.js : un hub d'événements centralisé qui permet aux composants de communiquer, peu importe où ils se trouvent dans l'arborescence des composants. Étant donné que les instances Vue implémentent l'interface de l'émetteur d'événements, vous pouvez en fait utiliser une instance Vue vide à cette fin :

var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', function (id) {
 // ...
})

Ce modèle peut remplacer $dispatch et $broadcast dans des scénarios simples. Mais pour les cas plus complexes, il est recommandé d'introduire une couche de gestion d'état dédiée à l'aide de Vuex .

L'exemple montré sur le guide de mise à niveau est le même que celui dont vous parlez

À propos de la communication récursive : plusieurs composants peuvent écouter le même événement. Cet événement est reconnu par le parent commun afin que chaque enfant puisse en être conscient

@posva , merci pour vos informations. le concentrateur de bus fonctionne vraiment bien dans une communication simple point à composant unique à point unique. S'il y a plusieurs composants avec le même type de composant, il y aura un problème, malheureusement, c'est un cas normal. Dans de nombreux cas, ce que je veux utiliser event est de mettre à jour une petite donnée appartenant à un composant spécifique. L'implémentation actuelle du bus d'événements ne donne pas d'informations sur le nœud de destination ou d'origine ( j'ai vu le _uid de chaque composant, peut-être pouvons-nous utiliser ce _uid unique pour le câblage de l'événement ? ), donc vuejs2.0 ne peut pas prendre en charge la communication d'événement point à point en fait . Pour être exact, le bus d'événements vuejs2.0 ne prend en charge que la communication de type de composant à type de composant ? Existe-t-il une solution simple pour répondre à cette exigence : déclenchée par un événement dans l'arborescence et mettre à jour SES PROPRES DONNÉES
vuex est idéal pour la gestion globale des données d'état statique au niveau de l'application, mais si je comprends bien, ce n'est peut-être pas bon pour la gestion des données de composants locaux spécifiques ?
Plus de réflexion est la bienvenue sur cette question.

@cnweibo J'ai répondu à votre question avec un exemple sur le forum. Je pense que cet exemple comblera vos besoins.
http://forum.vuejs.org/topic/4832/vue2-0-event-bus-issue-how-to-deliver-event-to-parent-when-the-same-multiple-parent-children-in- dom/6

Existe-t-il une solution simple pour répondre à cette exigence : déclenchée par un
événement dans l'arborescence et mettre à jour SES PROPRES DONNÉES

Ceci est résolu simplement par vuex, sans système d'événements compliqué.

vuex est idéal pour la gestion globale des données d'état statique au niveau de l'application,
mais si je comprends bien, ce n'est peut-être pas bon pour les données de composants locaux spécifiques
la gestion

« local » signifie un seul composant uniquement. Votre cas d'utilisation gère l'état à travers
plusieurs composants, donc c'est global.
Et vuex peut avoir des modules (sous-arbres d'état), donc ce n'est pas une "variable globale"
sorte de « mondial ». Vous pouvez piloter des groupes de composants avec leur propre vuex
modules.

Toute cette discussion «événements contre États partagés» a été réglée des mois
il y a, et la conclusion est d'utiliser soit le bus d'événements global, soit vuex. Alors je
vous recommandons d'en savoir plus sur vuex et son fonctionnement.

Le jeu. 1er sept. 2016, 16:17 cnweibo [email protected] a écrit :

@posva https://github.com/posva , merci pour vos informations. Le bus
le hub fonctionne vraiment bien dans un simple point de composant unique à un seul composant
communication ponctuelle. S'il y a plusieurs composants avec le même composant
type, il y aura un problème, malheureusement, c'est un cas normal. De nombreux
cas, ce que je veux utiliser événement est de mettre à jour une petite donnée appartenant à certains
composant spécifique. La mise en œuvre du bus d'événements en cours ne donne pas
informations sur le nœud de destination ou d'origine (j'ai vu _uid de chaque
composant, peut-être pouvons-nous utiliser ce _uid unique pour le câblage de l'événement ? ), donc
vuejs2.0 ne peut en fait pas prendre en charge la communication d'événements point à point. Être
exact, le bus d'événement vuejs2.0 ne prend en charge que le type de composant à type de composant
la communication? Existe-t-il une solution simple pour répondre à cette exigence :
déclenché par un événement dans l'arborescence et mettre à jour _SES PROPRES DONNÉES_
vuex est idéal pour la gestion globale des données d'état statique au niveau de l'application,
mais si je comprends bien, ce n'est peut-être pas bon pour les données de composants locaux spécifiques
la gestion?

Plus de réflexion est la bienvenue sur cette question.

-
Vous recevez ceci parce que vous êtes abonné à ce fil.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/vuejs/vue/issues/3581#issuecomment -244008699, ou couper le son
le fil
https://github.com/notifications/unsubscribe-auth/AFTLl1bjHqWTVDAkr8Fqbx0WiTuH16n2ks5qlooBgaJpZM4JyUfJ
.

Je vais maintenant clore ce sujet, car

  1. Des solutions ont été apportées et
  2. Les problèmes de Github ne sont pas le bon endroit pour demander de l'aide de toute façon (voir les directives)

@ktsn , merci pour votre violon de démonstration. C'est exactement ce que je veux une solution simple!
@fnlctrl , je passerai plus de temps sur la soi-disant gestion d'état vuex modulaire

merci encore ~!

À mon avis, $broadcast n'est pas nécessaire, seul le flux de données des accessoires en baisse.
Tout $dispatch peut être réimplémenté en tant que v-on et $emit à un seul niveau comme ceci (dans Vue 1) :
<child-component @select="$emit('select', $arguments[0])" /> sur chaque composant impliqué
Dans toute autre situation, des bus d'événements personnalisés doivent être utilisés

Vraiment, le v-on sur la balise du composant pour l'événement personnalisé sur le composant lui-même fonctionne également avec $emit du composant lui-même.

@cnweibo Pour mémoire, les données de l'événement peuvent être récupérées.

{
  template: `<foo @bar="dosomething">`,
  methods: {
    dosomething(params1, params2, ... and all the event data args) {}
  }
}

Mais les données de l'événement ne peuvent pas être récupérées dans vuejs2.0

Bien sûr que oui, qu'est-ce qui te fait penser le contraire ?

@fnlctrl
@LinusBorg
Désolé, j'ai un malentendu et rend les choses pas claires. dans le modèle @fnlctrl fourni, peut vraiment récupérer toutes les données dans son gestionnaire d'événements même avec

 <comp @some-event-emitted-by-comp-internal-template="someFuncInParentScope"></comp>

Copiez/collez mon propre commentaire d'un autre numéro : https://github.com/vuejs/vue/issues/2760#issuecomment -250883407

Je pense que la suppression de $dispatch était une idée terrible. Ce n'était pas le premier framework/bibliothèque d'interface utilisateur à implémenter la notion d'actions/événements bouillonnants dans un arbre visuel. C'est une idée bien établie. Pourquoi supprimer cette fonctionnalité en partant du principe que « être capable de déclencher un événement qui provoque des effets secondaires dans son arbre parent inconnu me semble être une recette pour des ennuis » ? Vous devez laisser cette responsabilité aux utilisateurs. Je suis sûr que la plupart ont le bon sens pour utiliser cette fonctionnalité de manière appropriée. Ce n'est pas un nouveau concept !

Je ne vois vraiment pas l'avantage de ce changement lorsque cette bibliothèque est construite sur des technologies/concepts Web établis de longue date tels que les événements DOM et DOM qui font en fait bouillonner l'arbre visuel et le font depuis des années sans personne se plaindre. L'idée de composants n'est-elle pas quelque chose qui a été adopté récemment grâce à la proposition du W3C pour les composants Web ? À mon avis, il est logique que les composants Vue se comportent de la même manière que les éléments DOM normaux en ce qui concerne la gestion des événements.

L'alternative proposée pour utiliser un bus d'événements global me semble illogique alors qu'il existait déjà quelque chose de plus pratique, efficace et plus facile à comprendre (car c'est un concept bien établi depuis des années).

D'autres propositions dans ce fil me rappellent comment EmberJS veut le faire. Transmettre les actions de fermeture en tant que propriétés aux composants à chaque niveau de la hiérarchie. Tellement fastidieux et inutile ! Vuejs était la raison pour laquelle j'ai écrit https://www.npmjs.com/package/ember-component-action-bubbling !

A part ça, j'aime beaucoup ta bibliothèque. Mais sérieusement, je pense que c'était un changement terrible.

Le paradigme du bus d'événements n'a été proposé que comme solution pour faire exactement la même chose, alors qu'une architecture basée sur les événements est souvent inférieure à une architecture déclarative basée sur l'état.

Disons que vous avez une application où l'utilisateur peut se connecter. Avec une solution basée sur les événements :

  1. Écouter un événement de connexion
  2. Déclenchez l'événement plus tard avec le nom d'utilisateur et le mot de passe
  3. Répondez à cet événement en conséquence, quels que soient les composants à l'écoute

Cela vient avec quelques problèmes, cependant. Le plus important étant que les composants qui ne sont pas rendus dans le DOM lorsque l'événement est déclenché ne recevront pas le changement, et vous ne savez pas du tout quelles parties de l'application recevront l'événement. De plus, les récepteurs de l'événement ne peuvent pas savoir d'où vient l'événement sans que des informations supplémentaires soient fournies. Excusez mon langage, mais c'est un énorme clusterfuck que j'ai traité et que je n'ai pas envie d'utiliser à nouveau.

Utilisons donc une approche avec état :

  1. Créez une variable d'état globale représentant les informations du compte utilisateur. Il s'agit de null lorsqu'il est déconnecté et contient les informations de connexion de l'utilisateur lorsqu'il est connecté.
  2. Lorsque l'utilisateur se connecte, définissez les informations du compte.

Tout dans l'application qui repose sur cette variable d'état est mis à jour en conséquence. Aucun événement, et peu importe quand ou où le composant est créé, car il affichera toujours les informations correctes. Vous pouvez utiliser un événement pour mettre à jour l'état global, mais pourquoi le faire alors que vous pouvez simplement… le mettre à jour ?

Une approche déclarative vous permet d'écrire vos composants de manière à ce qu'ils apparaissent toujours de la même manière en fonction de l'état local/global, indépendamment de ce que l'utilisateur fait dans votre application, sans avoir à écouter les événements. Je crois que c'est ce à quoi Vue était destiné depuis le début, mais comme pour la plupart des choses dans le développement de logiciels, il nous a fallu un certain temps pour comprendre cela. Mais je suis sacrément content que nous l'ayons fait.

EDIT : Oh, et n'oubliez pas que vous pouvez surveiller les paramètres et, par exemple, envoyer une requête AJAX ou effectuer une autre action lorsqu'elle change. par exemple, après qu'un utilisateur se soit connecté, regardez la variable 'loggedIn', quand c'est vrai, chargez ses images de profil, ou quelque chose comme ça.

Je comprends ce que vous dites, mais avoir un composant aléatoire qui modifie l'état global est, je pense, la même chose que d'avoir ce composant aléatoire qui fait remonter un événement à Dieu sait où. Vous courez toujours le même risque que le flux de votre application "sale" accidentellement.

Il existe des moyens de gérer les deux paradigmes de manière propre et cela finira généralement (et devrait) par être la responsabilité de l'utilisateur du framework.

Il y aura certaines situations où un mécanisme aura plus de sens que l'autre. Par exemple, je suis d'accord qu'un état de connexion doit être connu de toute votre application : l'état global a du sens. Mais le bouton sur lequel l'utilisateur de l'application clique ne gère généralement pas la logique derrière la connexion réelle de l'utilisateur. Ce sera quelque chose qui sera géré plus haut dans la chaîne. Cela peut être un composant, peut-être une route. Le bouton n'aura probablement besoin que de notifier quelque chose de l'intention de se connecter. Le bouton n'a donc pas besoin de modifier directement votre état global.

Alors maintenant, avec la suppression de $dispatch, vous avez besoin du composant bouton pour connaître un objet global qui gère la session utilisateur de l'application et l'informer directement de l'intention. Cela rend le bouton étroitement lié à l'ensemble de votre application.

Ou, vous pourriez avoir le bouton imbriqué sur 10 niveaux et vous devriez déclarer un gestionnaire v-on:login à chaque niveau afin que l'intention atteigne sa destination. Totalement inutile.

En fait, devoir faire v-on à chaque niveau rend votre code plus difficile à maintenir.

Bien évidemment, changer directement l'état peut être problématique, mais Vuex résout ce problème avec des mutations et des actions. Et il est vrai que certaines solutions conviendront mieux que d'autres, mais je n'ai jamais rencontré de situation où la logique déclarative n'était pas la meilleure option.

Dans votre cas particulier, je ne ferais probablement pas de bouton spécifique à la connexion, heh. En complément, si un composant lié à la connexion est imbriqué aussi profondément pour une raison quelconque, faites-lui simplement muter l'état global.

Le bouton de connexion n'était qu'un exemple. Et un magasin vuex est ce à quoi je faisais référence lorsque j'ai mentionné "quelque objet global". Il faudrait que je me penche sur le fonctionnement de vuex, mais je suppose que vous associez étroitement un composant aléatoire au reste de l'état de votre application en devant simplement gérer une référence au magasin.

Ce n'est pas souhaitable si, par exemple, le bouton de connexion faisait partie d'une bibliothèque tierce.

Je souhaite vraiment que vous n'ayez pas supprimé le *_choix *_ d'utiliser l'un ou l'autre paradigme, en particulier lorsque le bouillonnement d'événements est largement reconnu et donc facile à comprendre pour les nouveaux contributeurs sur un projet.

Cela dépend de ce que vous entendez par "un composant aléatoire", car un composant de vue de routeur, par exemple, a tous les droits d'accès et de validation au magasin à mon avis. Cependant, s'il s'agit d'un composant plus petit à réutiliser, tel qu'un bouton, un formulaire ou un autre élément d'interface utilisateur, 9 fois sur 10, il ne devrait y avoir aucune raison logique pour qu'il accède au magasin, en utilisant des accessoires et des événements.

Étant donné que les données d'une application Vue sont descendantes, vous souhaitez conserver autant de votre état local que possible. La nidification profonde en elle-même est un problème à éviter autant que possible. Ce n'est pas _que_ trop gênant de propager des événements de deux niveaux vers le bas, mais il y a de fortes chances que vous deviez repenser la structure de votre modèle si elle va plus loin que cela.

C'est surtout une tangente, cependant. Souvent, les paradigmes les plus faciles à comprendre sont ceux qui finissent par être maltraités jusqu'au bout de l'enfer et deviennent difficiles à manier. Une approche basée sur l'état est beaucoup plus simple, comme convenu par la plupart d'entre nous qui utilisons actuellement 2.0. Vous êtes libre de continuer à utiliser la 1.0, ou de passer à un autre framework si cette approche ne vous convient pas.

9 fois sur 10, il ne devrait y avoir aucune raison logique pour qu'il accède au magasin, en utilisant des accessoires et des événements.

Exactement mon propos.

La nidification profonde en elle-même est un problème à éviter autant que possible

Parfois, ce n'est pas une option.

Ce n'est pas si compliqué de propager des événements à deux niveaux

Ce n'est pas si vrai lorsque ces niveaux vont plus loin.

les paradigmes les plus faciles à comprendre sont ceux qui finissent par être maltraités jusqu'au bout de l'enfer et deviennent difficiles à manier

Cela devrait dépendre de la discipline de vos utilisateurs.

Vous êtes libre de continuer à utiliser la 1.0, ou de passer à un autre framework si cette approche ne vous convient pas.

Mmk.

La simplicité et la commodité sont la raison pour laquelle j'envisageais de passer d'Ember à Vue. $dispatch est l'une des choses que j'ai appréciées à propos de Vue et sa suppression me semble si arbitraire.

L'équipe a supprimé de nombreuses fonctionnalités pour la version 2.0. Je suis honnêtement d'accord avec chacun d'eux. Pas celui-ci.

Merci pour vos réponses.

@ktsn Les alternatives à $broadcast et $dispatch sont très simples, cette suppression s'est améliorée et s'est améliorée.

@rhyek Je voudrais donner mon 2ct sur quelques points que vous avez soulevés. Étant donné que la discussion a déjà abordé un certain nombre de sujets, j'aimerais revenir à l'essentiel sur les raisons pour lesquelles nous avons déprécié $diospatch et $broacast :

1. couplage implicite.

Si vous avez un parent et un enfant profondément imbriqué qui distribue un événement, il n'y a aucun moyen de déduire cette relation à partir du code (et il en va de même pour $broadcast , évidemment.)

Si vous regardez les autres modifications et dépréciations que nous avons introduites avec Vue 2.0, vous vous rendrez peut-être compte que la suppression du comportement implicite en faveur d'alternatives explicites est un thème commun, et la dépréciation de $dispatch adapte parfaitement.

Exemple:

// parent
events: {
  'some-event': function () { ... }
}

// deeply nested child:
$dispatch('some-event')

C'est bien lorsque le parent n'a qu'un seul enfant direct - mais dans ce cas, $emit() avec un écouteur dans le modèle n'est pas non plus un vrai travail supplémentaire.

Il devient difficile de suivre (surtout en équipe) dès que vous avez des enfants imbriqués (surtout profondément imbriqués), ou même plus d'un enfant direct - vous devez soit parcourir tous les enfants, soit vous fier aux commentaires du code pour documenter quel événement est déclenché à partir de quel composant enfant - qui est également un passe-partout supplémentaire.

Vous dites que vous aimez $dispatch et $broadcast parce que vous n'avez pas à les faire passer par d'autres composants. Et je peux convenir que c'est plus facile - mais nous n'avons pas rencontré beaucoup de situations où cela était réellement nécessaire, ou plutôt : s'il y avait une telle chaîne de transmission d'un événement, ce serait plutôt le cas que les données seraient modifiées/ en annexe/ pendant ce voyage par composante intermédiaire.

2. Noms des événements

lorsque vous utilisez $dispatch avec des composants profondément imbriqués, vous devez être très explicite dans l'espacement des noms de vos événements, car sinon, ils pourraient entrer en conflit :

// parent
events: {
  'close': function () { ... }
}

// deeply nested child 1:
$dispatch('close')
// deeply nested child 2:
$dispatch('close')

..et si ces enfants sont des bibliothèques tierces, vous êtes foutu maintenant. ou devez attraper l'événement dans un composant au milieu juste pour le renommer avant de $dispatch() plus loin jusqu'au parent. Et n'oubliez pas de commenter cela, car quelqu'un qui regarde ce code pourrait penser pourquoi vous ne faites rien d'autre avec un événement que de le renommer.

L'utilisation de $emit et de modèles d'écoute n'a pas ce problème. vous pouvez utiliser des noms d'événement simples et courts partout, ils n'entreront pas en conflit car chaque événement a son propre rappel attaché dans le modèle @close="callback ".

Je souhaite vraiment que vous n'ayez pas supprimé le *choix* d'utiliser l'un ou l'autre paradigme,

Si nous pensions que les deux paradigmes peuvent fonctionner aussi bien, nous les traiterions de la même manière. Mais nous ne le pensons pas, pour les raisons ci-dessus et plus encore.

Par conséquent, nous essayons d'orienter les utilisateurs vers les stratégies que nous avons trouvées les plus efficaces, tout en laissant un moyen de les contourner avec la méthode du "Bus global".

J'aimerais également parler de vos inquiétudes concernant l'état mondial, mais je ne suis pas sûr de bien comprendre votre position pour le moment.

Peut-être pouvez-vous fournir un exemple où vous pensez que $dispatch et $broadcast fonctionnent le mieux pour vous, et j'essaie de vous montrer comment "notre" approche pourrait améliorer la situation ?

Je pense que $dispatch/$broadcast et le bus d'événements abordent des choses différentes. Ils peuvent rendre le code facile à maintenir et découplé sur différents scénarios. Si nous pouvons les garder tous les deux, ce sera génial.
Il est très difficile de dire que l'un est meilleur que l'autre dans tous les cas.

@cnweibo Je pense qu'il y a eu des arguments assez exhaustifs des deux côtés, et honnêtement, je ne vois pas votre point de vue sur "aborder des choses différentes". N'hésitez pas à faire d'autres arguments, mais je peux vous dire avec certitude que cela n'arrivera pas.

Si vous le voulez vraiment, ce n'est pas si difficile de l'implémenter vous-même en tant que plugin.

@LinusBorg J'apprécie vraiment le temps que vous avez pris pour écrire votre réponse et je comprends vos arguments.

Vous dites que vous aimez $dispatch et $broadcast

J'aime juste $dispatch , honnêtement. $broadcast m'a vraiment semblé étrange. Comme je l'ai dit, $dispatch n'est qu'un bouillonnement d'événements qui est quelque chose d'omniprésent parmi de nombreuses plates-formes à ce stade. $broadcast ... pas tellement. La seule chose similaire que j'ai jamais rencontrée, ce sont les événements de "prévisualisation" dans WPF qui sont associés à des événements normaux. Ils "tunnel" le long de l'arborescence visuelle de l'élément le plus haut à la source de l'événement d'origine, mais ils ne sont envoyés que directement dans la chaîne des éléments liés et ne se propagent pas à tout.

il faudrait être très explicite dans l'espacement des noms de vos événements

Je suis d'accord avec ça et c'est généralement ce que je fais, de toute façon. C'est aussi ce que les gens ont l'habitude de faire sur jQuery. De plus, certaines plates-formes envoient simplement un objet "source" comme argument au gestionnaire et vous pouvez peut-être filtrer les contextes en fonction de cela (indice : instanceof ). Les événements DOM ont event.target disponibles, par exemple. D'autres plates-formes ont l'avantage de travailler avec des types statiques, ce "clash" est donc assez difficile à rencontrer (un événement est une instance d'une classe).

En tout cas, honnêtement, je ne comprends pas pourquoi cela préoccupe autant l'équipe VueJS. Si les gens ne font pas assez attention à l'utilisation de $dispatch , je suis sûr que vous pourriez trouver beaucoup d'autres choses qu'ils font mal en utilisant votre bibliothèque. Jusqu'où irez-vous pour "protéger" vos utilisateurs de l'imprudence ?

C'est bien quand le parent n'a qu'un seul enfant direct - mais dans ce cas, $emit() avec un écouteur dans le modèle n'est pas non plus un vrai travail supplémentaire.

Question honnête (car je suis décidément nouveau sur Vue), en plus de déclarer des auditeurs à tous les niveaux, ne devez-vous pas également $emit l'événement sur chaque composant de la chaîne ? Cela semble tellement ennuyeux.

En conclusion, permettez-moi de citer quelque chose que quelqu'un a dit sur un problème sur vue-cli à propos de l'introduction de "modèles officiels" pour les nouveaux projets (https://github.com/vuejs/vue-cli/issues/123#issuecomment-233071630):

Comme vous le savez probablement, vous n'êtes pas limité aux modèles officiels. Cela vous donne de la liberté, mais en même temps, cela vous oblige à prendre plus de décisions vous-même.

Je pense qu'à la fin tout n'est qu'un mètre d'équilibre. Combien de ces décisions pouvons-nous prendre à l'avance pour tous (la plupart) de nos utilisateurs et combien ou lesquelles les utilisateurs veulent prendre eux-mêmes.

Je suis d'accord avec cette philosophie, mais ce n'est pas la même attitude que j'ai rencontrée à propos de ce problème, étrangement. Le contraste que je vois entre ce commentaire et les commentaires ici se résume à la liberté. Vous supprimez des choix basés sur des intentions, bien que bonnes, mais finalement erronées.

Si vous le voulez vraiment, ce n'est pas si difficile de l'implémenter vous-même en tant que plugin.

@yyx990803 C'est probablement ce que _je vais_ finir par faire... probablement.

@LinusBorg aussi :

Par conséquent, nous essayons d'orienter les utilisateurs vers les stratégies que nous avons trouvées les plus efficaces, tout en laissant un moyen de les contourner avec la méthode du "Bus global".

Vous n'êtes pas "en train d'essayer de diriger", vous forcez. :)

Avez-vous essayé d'implémenter la même fonctionnalité avec les méthodes dispatch et EventBus ?
ça peut aider

@posva Je prévois de le faire, mais je veux dire, vous déclarez essentiellement l'objet de bus d'événements sur un module, et vous l'importez partout où vous voulez $emit , non? Je n'aime pas ça, tbh. Je vais certainement l'utiliser pour certaines choses, mais je crois fermement que ce n'est pas ce que je veux faire à chaque fois.

En tout cas, honnêtement, je ne comprends pas pourquoi cela préoccupe autant l'équipe VueJS. Si les gens ne font pas assez attention à l'utilisation de $dispatch ,

Eh bien, le fait est que personne dans l'équipe n'a pu signaler un cas d'utilisation réel pour $dispatch() dans lequel il était préférable à d'autres solutions (non seulement $emit() , mais aussi un bus, ou état global), et nous n'en avons pas vu non plus dans les innombrables messages sur le forum auxquels nous avons répondu.

Cela peut être un point de vue subjectif, mais peut-être pouvez-vous comprendre que si toute l'équipe pense que "c'est, selon notre expérience, toujours une solution inférieure", nous la supprimons du noyau.

À ce stade, je veux renouveler mon offre pour discuter d'un exemple réel.

Je suis sûr que vous pourriez trouver beaucoup d'autres choses qu'ils font mal en utilisant votre bibliothèque. Jusqu'où irez-vous pour "protéger" vos utilisateurs de l'imprudence ?

C'est bien sûr une question délicate et un équilibre difficile à trouver. Nous devrons juger au cas par cas.

C'est bien quand le parent n'a qu'un seul enfant direct - mais dans ce cas, $emit() avec un écouteur dans le modèle n'est pas non plus un vrai travail supplémentaire.

Question honnête (car je suis décidément nouveau sur Vue), en plus de déclarer des auditeurs à tous les niveaux, ne devez-vous pas également émettre l'événement sur chaque composant de la chaîne ? Cela semble tellement ennuyeux.

Puisque je parle de relations directes parent-enfant, vous n'auriez qu'à $emit() une fois.

Si vous avez des enfants profondément imbriqués, bien sûr, vous devez réémettre à tous les niveaux, mais me répéter : nous n'avons pas trouvé ni présenté de situations qui répartissaient de nombreux enfants imbriqués est vraiment nécessaire ou préférable à d'autres solutions.

Par conséquent, nous essayons d'orienter les utilisateurs vers les stratégies que nous avons trouvées les plus efficaces, tout en laissant un moyen de les contourner avec la méthode du "Bus global".

Vous n'êtes pas "en train d'essayer de diriger", vous forcez. :)

Je dirais que nous rendons votre vie un peu plus difficile - vous pouvez

  • utiliser un bus, ce qui n'est pas la même chose mais peut avoir un comportement similaire dans la plupart des cas.
  • réimplémentez cela en tant que plugin assez facilement.

Nous ne vous forçons pas à utiliser $emit() , nous rendons simplement votre chemin un peu plus difficile.

Je pense que vous pouvez également l'ajouter à chaque instance de Vue : Vue.prototype.$bus = new Vue()
Ne pas aimer quelque chose n'est pas très constructif...
J'attends vos exemples

@posva

Je pense que vous pouvez également l'ajouter à chaque instance de Vue : Vue.prototype.$bus = new Vue()

J'aime ça. Assez intelligent.

Ne pas aimer quelque chose n'est pas très constructif

Je pense que c'est un critère assez valable pour choisir d'utiliser quelque chose ou non, du moins pour moi. En tout cas, j'ai expliqué à plusieurs reprises pourquoi je pense que le bouillonnement d'événements a sa place.

J'attends vos exemples

Je veux dire, en ai-je vraiment besoin ? J'ai donné des exemples de situations où je n'aime pas l'idée d'utiliser un bus d'événements ou de déclarer des auditeurs à tous les niveaux. Vous voulez voir le code ? Je pourrais peut-être proposer quelque chose pour clarifier un peu mon propos, mais je pense que le bouillonnement d'événements est une chose assez standard que la plupart des gens peuvent apprécier comme quelque chose d'utile, et les bus événementiels ou les gestionnaires d'état sont, au moins pour moi, une sorte de changement de paradigme qui, bien que pas difficile à comprendre, semble être un territoire hipster. ??

Je plaisante bien sûr sur ce dernier commentaire. Comme je l'ai déjà dit, je vois leurs utilisations et je trouverai certainement un problème à résoudre avec eux. En fait, sur certains projets sur lesquels j'ai travaillé avec Ember, j'ai tendance à écrire un "service" qui agit exactement comme un gestionnaire d'état global. Je vous assure que je n'essaie pas de m'entêter à dessein.

J'aime beaucoup Vue. Je veux juste _l'aimer_, tu sais ?

ne devez-vous pas également $émettre l'événement sur chaque composant

Vous le faites si vous pensez en termes de bouillonnement d'événements. Et vous ne le faites pas si vous utilisez la composition de composants.

Par exemple:

<div>
  <a-button @click="modalShown = true">Open modal</a-button>
  <a-modal v-if="modalShown">
    <a-button @click="modalShown = false">Close modal</a-button>
  </a-modal>
</div>

a-modal composant a-button , car les deux instances a-modal et deux a-button sont des « enfants logiques directs » d'une seule instance , malgré une hiérarchie de vues compliquée avec l'imbrication.

Je pense que je ne fais que me répéter à ce stade. Je finirai par contourner ce problème, d'une manière ou d'une autre. Il me semble juste étrange que cette discussion ait tourné autour de l'indication de plusieurs solutions de

@LinusBorg :

Eh bien, le fait est que personne dans l'équipe n'a pu signaler un cas d'utilisation réel pour $dispatch() dans lequel il était préférable à d'autres solutions (pas seulement $emit()

Cela me semble être un ingénieur civil me demandant une raison pour ne pas fermer une sortie d'autoroute :

Il dit quelque chose comme : « Cette bretelle de sortie mène à une intersection où les gens ne savent pas s'il faut tourner à gauche ou à droite. La plupart des gens connaissent le chemin parce qu'ils vivent ici depuis des années, mais les nouveaux citoyens se perdent souvent pendant quelques années. minutes et nous voulons éviter cela."

Je dis : "D'accord, bien sûr, vous pouvez le fermer, c'est cool. Je vais devoir parcourir 10 km plus loin jusqu'à la prochaine bretelle de sortie.

:) Merci à tous pour vos réponses. Je suis content que vous soyez tous ouverts à la discussion, au moins. Ça a l'air d'être une bonne équipe.

Cela me semble être un ingénieur civil me demandant une raison pour ne pas fermer une sortie d'autoroute :

Il dit quelque chose comme : « Cette bretelle de sortie mène à une intersection où les gens ne savent pas s'il faut tourner à gauche ou à droite. La plupart des gens connaissent le chemin parce qu'ils vivent ici depuis des années, mais les nouveaux citoyens se perdent souvent pendant quelques années. minutes et nous voulons éviter cela."

J'ajouterai aussi ma mauvaise métaphore. :) À mon avis, c'est plutôt :

  • "Cette route encourage les gens à courir plus vite qu'ils ne le devraient. Les limites de vitesse sont rarement respectées. Nous devrions ajouter des pare-chocs pour forcer les gens à ralentir."
  • "Mais j'aime arriver à destination rapidement en accélérant !"
  • "Bien sûr, cela peut vous servir bien quelques fois, mais nous observons cette partie de la route en permanence depuis plus d'un an et demi, et le nombre d'accidents et de personnes manquant la prochaine bretelle de sortie n'en vaut tout simplement pas la peine, car de nombreux conducteurs qui ont eu l'un de ces problèmes en a attesté."
  • "Mais je n'aime pas ces pare-chocs!"
  • Eh bien, pour 99% des destinations, cette autre route est aussi rapide que celle-ci l'était avant les pare-chocs, il suffit de prendre celle-ci.
  • "Mais je n'aime pas cette autre route ! La vue n'est pas aussi belle !"
  • ...

Ne pas aimer quelque chose n'est pas très constructif

Je pense que c'est un critère assez valable pour choisir d'utiliser quelque chose ou non, du moins pour moi. En tout cas, j'ai expliqué à plusieurs reprises pourquoi je pense que le bouillonnement d'événements a sa place.

Je pense que @posva voulait dire : "J'aime ça" n'est pas un argument constructif lorsque l'on discute de la possibilité de conserver quelque chose ou d'ajouter quelque chose à la bibliothèque avec un large éventail d'utilisateurs. C'est pourquoi je continue à demander un cas d'utilisation valable et réel à discuter au lieu de préférences personnelles.

Ouais, sauf que tu as fait exploser la très bonne autoroute et en a construit une autre avec de l'asphalte caoutchouté parce que tu as lu quelque part que c'est plutôt chouette. De plus, c'est 10 km supplémentaires. :)

À propos de l'exemple : je pense que celui publié sur la question d'origine sur les composants récursifs est correct. Imaginez simplement que vous vouliez faire quelque chose à tous les niveaux dans l'ordre lorsqu'un événement est détecté et que vous avez un parfait exemple. Faire cela avec $dispatch est assez simple.

Vous voulez voir le code ?

Oui s'il vous plaît

@posva J'ai donné un exemple sur le commentaire précédent. Remarque : si vous devez réfléchir plus de quelques secondes à la manière de le faire sans $dispatch, cela prouve mon point de vue.

À propos de l'exemple : je pense que celui publié sur la question d'origine sur les composants récursifs est correct. Imaginez simplement que vous vouliez faire quelque chose à tous les niveaux dans l'ordre lorsqu'un événement est détecté et que vous avez un parfait exemple. Faire cela avec $dispatch est assez simple.

avec $dispatch()

// recursive-child
<template>
  <recursive-child></recursive-child>
  <button @click="dispatch">Do something</button>
<template>

<script>
  export default{
    methods: {
      dispatch() { this.$dispatch('do-something') }
    },
    events: {
      'do-something': function () { 
         // do something, or don't
         return true // nessessary to make the event bubble up further. Don't like the un-expressivness of this
       }
    }
  }
</script>

avec $emit()

// recursive-child
<template>
  <recursive-child @do-something="doSomething"></recursive-child>
  <button @click="doSometing">Do something</button>
<template>

<script>
  export default{
    methods: {
      doSomething() {
        // do someting, or don't
        this.$emit('do-something')
      }
    }
  }
</script>

Est-ce vraiment pire ?

Vous en avez un autre ? :)

OK, bien sûr. Et s'ils ne sont pas récursifs mais toujours imbriqués comme ça ?

Bien. Il est 5h du matin et je vais passer une journée difficile grâce à vous. Si je trouve quelque chose de mieux plus tard, je le posterai sinon, alors, soit vous avez gagné, soit j'ai perdu tout intérêt :)

Et s'ils ne sont pas récursifs mais toujours imbriqués comme ça ?

Vous devriez ajouter un écouteur @event= dans chaque modèle pour $emit() , et pas pour $dispatch() , c'est à peu près tout.

Cela peut être considéré comme bon ou mauvais, selon que vous insistez sur la verbosité par rapport à l'expressivité.

et d'ailleurs. si dans une situation vous devez enchaîner un événement jusqu'au parent, cela peut être fait quelque chose comme :

<child-comp @event="$emit('event', $arguments)>
  • Vous pleurerez le "couplage" que cela fait entre les composants.
  • Je louerai l'expressivité
  • A part ça, c'est un peu plus à taper mais ce n'est pas grave.
  • et je prétends toujours, avec un exemple de cas d'utilisation réel, qu'il existe probablement une optimisation différente disponible, comme un magasin global - mais cela dépend du scénario individuel et est difficile à argumenter avec un exemple de code.

En tout cas, belle discussion, profite bien de ton sommeil bien mérité.

@rhyek, cela ressemble à des solutions de contournement uniquement parce que vous avez décidé d'utiliser $dispatch en premier lieu, mais ce n'est pas le but. L'objectif est de permettre aux composants de communiquer entre eux avec une maintenabilité décente. Lorsque vous atteignez cet objectif, $dispatch est la solution inférieure lorsque vous énumérez tous les avantages et inconvénients pratiques, à l'exclusion des préférences, nous l'avons donc abandonné.

Notez également que le bouillonnement d'événements DOM est fondamentalement différent de la communication entre composants. L'argument selon lequel « le bouillonnement d'événements est largement reconnu » ne signifie pas que cela doit être une bonne solution pour le problème que nous essayons de résoudre.

J'ai fini de commenter dans ce fil parce que j'ai du mal à discuter avec "Je n'aime pas ça".

Cette page vous a été utile?
0 / 5 - 0 notes