Vue: ¿Debería vuejs2.0 mantener la api del evento $ broadcast, $ dispatch? No hay una buena solución para abordar la comunicación punto a punto entre padres e hijos en 2.0

Creado en 1 sept. 2016  ·  41Comentarios  ·  Fuente: vuejs/vue

@ yyx990803 ,
Hola, equipo central de vuejs:
Estoy luchando por encontrar una buena solución para la comunicación punto a punto entre los componentes padre-hijo con vuejs2.0.
Debido a que vuejs2.0 ha desaprobado la api $ broadcast, $ dispatch, es muy difícil para mí encontrar una solución alternativa $ broadcast, $ dispatch proporciona la función de bus de eventos vuejs2.0.
He escrito un hilo en el foro sobre este tema aquí , y me gustaría pegarlo aquí para más discusión.

POR FAVOR NO LO CIERRE A MENOS QUE tenga una buena idea o solución en vuejs2.0.

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

En el código anterior, cuando el hijo de pcom1, por ejemplo, soncoma $ emite un evento, digamos,

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

en el pcom, escuchamos ese evento con

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

Solo quiero que pcom1 maneje ese evento, pero desafortunadamente pcom2 también lo manejará.
¿Cómo abordar esta condición?

Una de las soluciones en mi aplicación es usar this. $ Parent como bus de eventos
En niño:

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

En padre:

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

El punto negativo de la solución anterior es:

  1. acoplamos mucho en la relación padre-hijo;
  2. no funciona si hay un nivel más profundo de niveles de padres e hijos;

En algunas condiciones más complejas, será más difícil encontrar una buena solución para el sistema de eventos personalizado, por ejemplo, un componente recursivo.

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

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

¿Cómo se comunica el niño recursivo con su componente pcom directo?
Por favor, dé su idea o señale sobre estos temas.
Gracias ~!

discussion

Comentario más útil

@rhyek Me gustaría dar mi 2ct sobre un par de puntos que planteaste. Dado que la discusión ya ha abordado una serie de temas, me gustaría volver a lo básico sobre por qué desaprobamos $ diospatch y $ broacast:

1. acoplamiento implícito.

Si tiene un padre y un hijo profundamente anidado que distribuye un evento, no hay forma de inferir esta relación del código (y lo mismo es cierto para $broadcast , obviamente).

Si observa los otros cambios y depreciaciones que introdujimos con Vue 2.0, es posible que se dé cuenta de que eliminar el comportamiento implícito a favor de alternativas explícitas es un tema común, y desaprobar $dispatch encaja perfectamente allí.

Ejemplo:

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

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

Esto está bien cuando el padre solo tiene un hijo directo, pero en ese caso, $emit() con un oyente en la plantilla tampoco es un trabajo adicional real.

Se vuelve difícil de seguir (especialmente en equipos) tan pronto como tiene hijos anidados (especialmente anidados profundamente), o incluso más de un hijo directo: debe revisar todos los hijos o confiar en los comentarios del código para documentar qué evento es a partir de qué componente hijo, que también es un texto estándar adicional.

Dices que te gustan $ dispatch y $ broadcast porque no tienes que pasarlos a través de otros componentes. Y puedo estar de acuerdo en que es más fácil, pero no nos hemos encontrado con muchas situaciones en las que esto sea realmente necesario, o más bien: si hubiera tal cadena de pasar un evento, preferiría que los datos se cambiaran / adjunto / durante este viaje por componente intermedio.

2. Nombres de eventos

cuando usa $dispatch con componentes profundamente anidados, tendría que ser muy explícito en el espacio de nombres de sus eventos, porque de lo contrario, podrían estar en conflicto:

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

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

..y si esos niños son bibliotecas de terceros, estás jodido ahora. o tener que capturar el evento en algún componente en el medio solo para cambiarle el nombre antes de $dispatch() más arriba del padre. Y no olvide comentar esto, porque alguien que esté mirando este código podría pensar por qué no hace nada más con un evento que cambiarle el nombre.

El uso de $ emit y oyentes de plantillas no tiene este problema. Puedes usar nombres de eventos cortos y simples en todas partes, no chocarán ya que cada evento tiene su propia devolución de llamada adjunta en la plantilla @close="callback ".

Realmente desearía que no te quitaras la * opción * de usar cualquiera de los paradigmas,

Si pensáramos que ambos paradigmas pueden funcionar igualmente bien, los trataríamos por igual. Pero no pensamos eso, por las razones anteriores y más.

Por lo tanto, tratamos de guiar a los usuarios hacia los pactos que encontramos que funcionan mejor, dejando una forma de evitarlo con el método del "bus global".

También me gustaría hablar sobre sus preocupaciones sobre el estado global, pero aún no estoy seguro de haber entendido completamente su posición.

Tal vez pueda proporcionar un ejemplo en el que crea que $ dispatch y $ broadcast funcionan mejor para usted, y yo trato de mostrarle cómo "nuestro" enfoque podría mejorar la situación.

Todos 41 comentarios

Debido a que es una discusión de propuesta general, todavía no he creado el violín. Si es necesario, me gustaría crear para demostrar.
gracias ~!

Esto ya se ha justificado en los cambios 2.0.

Aquí tienes una copia:

¿Cómo lidiar con la depreciación de $dispatch y $broadcast ?

La razón por la que estamos desaprobando $dispatch y $broadcast es que los flujos de eventos que dependen de la estructura del árbol de componentes pueden ser difíciles de razonar sobre cuándo el árbol de componentes se vuelve grande (en pocas palabras: no es así escale bien en aplicaciones grandes y no queremos que se sienta en problemas más adelante). $dispatch y $broadcast tampoco resuelven la comunicación entre componentes hermanos. En su lugar, puede usar un patrón similar al EventEmitter en Node.js : un centro de eventos centralizado que permite que los componentes se comuniquen, sin importar dónde se encuentren en el árbol de componentes. Debido a que las instancias de Vue implementan la interfaz de emisor de eventos, en realidad puede usar una instancia de Vue vacía para ese propósito:

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) {
 // ...
})

Este patrón puede servir como reemplazo de $dispatch y $broadcast en escenarios simples. Pero para casos más complejos, se recomienda introducir una capa de administración de estado dedicada usando Vuex .

El ejemplo que se muestra en la guía de actualización es el mismo del que está hablando

Acerca de la comunicación recursiva: varios componentes pueden escuchar el mismo evento. Este evento es reconocido por el padre común para que todos los niños puedan estar al tanto de él.

@posva , gracias por tu información. el concentrador de bus realmente funciona bien en una comunicación simple de un solo punto a un solo componente. Si hay varios componentes con el mismo tipo de componente, habrá un problema, desafortunadamente, este es un caso normal. En muchos casos, lo que quiero usar event es actualizar un pequeño dato perteneciente a algún componente específico. La implementación del bus de eventos actual no brinda información sobre el destino o el nodo de origen (he visto _uid de cada componente, ¿tal vez podamos usar este _uid único para el cableado del evento?), Por lo que vuejs2.0 no puede admitir la comunicación de eventos punto a punto de hecho . Para ser exactos, el bus de eventos vuejs2.0 solo admite comunicación de tipo de componente a tipo de componente. ¿Existe una solución simple para abordar ese requisito: desencadenado por un evento en el árbol y actualizar SUS PROPIOS DATOS?
vuex es excelente para la administración de datos de estado estático global a nivel de aplicación, pero según tengo entendido, ¿tal vez no sea bueno para la administración de datos de componentes locales específicos?
Se agradece una mayor reflexión sobre este tema.

@cnweibo He respondido a tu pregunta con un ejemplo en el foro. Creo que este ejemplo satisfará tus necesidades.
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 una solución simple para abordar ese requisito: desencadenado por un
evento en el árbol y actualizar SUS PROPIOS DATOS

Esto se resuelve simplemente con vuex, sin un complicado sistema de eventos.

vuex es ideal para la gestión de datos de estado estático global a nivel de aplicación,
pero según tengo entendido, tal vez no sea bueno para datos de componentes locales específicos
administración

'local' significa un solo componente. Su caso de uso está administrando el estado en
múltiples componentes, por lo que es global.
Y vuex puede tener módulos (subárboles de estado), por lo que no es una 'variable global'
tipo de 'global'. Puede impulsar grupos de componentes con su propio vuex
módulos.

Toda esta discusión de 'eventos versus estados compartidos' se ha resuelto meses
hace, y la conclusión es utilizar el bus de eventos global o vuex. Entonces yo
le recomiendo leer más sobre vuex y cómo funciona.

El jueves 1 de septiembre de 2016 a las 16:17, cnweibo [email protected] escribió:

@posva https://github.com/posva , gracias por tu información. el autobús
hub realmente funciona bien en un solo componente simple de punto a un solo componente
punto de comunicación. Si hay varios componentes con el mismo componente
type, habrá un problema, desafortunadamente, este es un caso normal. Muchos
casos, lo que quiero usar event es actualizar un pequeño dato que pertenece a algunos
componente específico. La implementación del bus de eventos actual no da
información sobre el destino o el nodo de origen (he visto _uid de cada
componente, tal vez podamos usar este _uid único para el cableado del evento. ), asi que
vuejs2.0 no admite la comunicación de eventos punto a punto de hecho. Ser
Exacto, el bus de eventos vuejs2.0 solo admite el tipo de componente al tipo de componente
¿comunicación? ¿Existe una solución simple para abordar ese requisito?
desencadenado por un evento en el árbol y actualizar _ SUS PROPIOS DATOS_
vuex es ideal para la gestión de datos de estado estático global a nivel de aplicación,
pero según tengo entendido, tal vez no sea bueno para datos de componentes locales específicos
¿administración?

Se agradece una mayor reflexión sobre este tema.

-
Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/vuejs/vue/issues/3581#issuecomment -244008699, o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AFTLl1bjHqWTVDAkr8Fqbx0WiTuH16n2ks5qlooBgaJpZM4JyUfJ
.

Ahora cerraré este problema, porque

  1. Se proporcionaron soluciones y
  2. Los problemas de Github no son el lugar adecuado para solicitar soporte de todos modos (consulte las Pautas)

@ktsn , gracias por tu violín de demostración. ¡Eso es exactamente lo que quiero una solución simple!
@fnlctrl ,

gracias de nuevo ~!

En mi opinión, $ broadcast no es necesario, solo el flujo de datos de los accesorios que caen.
Cualquier $ despacho se puede volver a implementar como v-on de un solo nivel y $ emitir así (en Vue 1):
<child-component @select="$emit('select', $arguments[0])" /> en cada componente involucrado
En cualquier otra situación, se deben utilizar buses de eventos personalizados.

Realmente, el v-on en la etiqueta del componente para el evento personalizado en el propio componente también funciona con $ emit desde el propio componente.

@cnweibo Para el registro, se pueden recuperar los datos del evento.

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

Pero los datos del evento no se pueden recuperar en vuejs2.0

Seguro que puede, ¿qué te hace pensar de otra manera?

@fnlctrl
@LinusBorg
Lo siento, tengo un malentendido y no dejo las cosas claras. en el patrón @fnlctrl proporcionado, realmente puede recuperar todos los datos en su controlador de eventos incluso con

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

Copiar / pegar mi propio comentario de otro problema: https://github.com/vuejs/vue/issues/2760#issuecomment -250883407

Creo que eliminar $ dispatch fue una idea terrible. Este no fue el primer marco / biblioteca de interfaz de usuario en implementar la noción de acciones / eventos de propagación en un árbol visual. Es una idea bien establecida. ¿Por qué eliminar esta funcionalidad con la premisa de que "poder enviar un evento que causa efectos secundarios en su árbol padre desconocido me suena como una receta para problemas"? Debe dejar esta responsabilidad a los usuarios. Estoy seguro de que la mayoría tiene el sentido común para utilizar esta función de forma adecuada. ¡No es un concepto nuevo!

Realmente no puedo ver el beneficio de este cambio cuando esta biblioteca se basa en tecnologías / conceptos web establecidos desde hace mucho tiempo, como los eventos DOM y DOM que, de hecho, hacen brotar el árbol visual y lo han estado haciendo durante años sin nadie. quejumbroso. ¿No es la idea de componentes algo que se ha adoptado recientemente gracias a la propuesta del W3C para componentes web? En mi opinión, solo tiene sentido que los componentes de Vue se comporten de manera similar a los elementos DOM regulares en lo que respecta a cómo se realiza el manejo de eventos.

La alternativa propuesta de usar un bus de eventos global me parece ilógica cuando ya existía algo más práctico, efectivo y más fácil de entender (por ser un concepto bien establecido desde hace años).

Otras propuestas en este hilo me recuerdan cómo EmberJS quiere hacerlo. Pasar acciones de cierre como propiedades a los componentes de cada nivel de la jerarquía. ¡Tan tedioso e innecesario! ¡Vuejs fue la razón por la que escribí https://www.npmjs.com/package/ember-component-action-bubbling!

Aparte de esto, me gusta mucho tu biblioteca. Pero en serio, creo que este fue un cambio terrible.

El paradigma de bus de eventos solo se propuso como una solución para hacer exactamente lo mismo, cuando una arquitectura basada en eventos a menudo es inferior a una arquitectura declarativa basada en estados.

Digamos que tiene una aplicación en la que el usuario puede iniciar sesión. Con una solución basada en eventos:

  1. Escuche un evento de inicio de sesión
  2. Dispare el evento más tarde con el nombre de usuario y la contraseña
  3. Responda a dicho evento en consecuencia en cualquier componente que esté escuchando

Sin embargo, esto viene con algunos problemas. El más importante es que los componentes que no se procesan en el DOM cuando se activa el evento no van a recibir el cambio, además de que usted no sabe qué partes de la aplicación recibirán el evento. Además, los receptores del evento no pueden saber de dónde proviene el evento sin información adicional. Disculpe mi lenguaje, pero he lidiado con un gran problema y no me importa usarlo de nuevo.

Entonces, usemos un enfoque con estado:

  1. Cree una variable de estado global que represente la información de la cuenta de usuario. Es null cuando cierra sesión y tiene la información de inicio de sesión del usuario cuando inicia sesión.
  2. Cuando el usuario inicie sesión, configure la información de la cuenta.

Todo en la aplicación que se basa en esta variable de estado se actualiza en consecuencia. Sin eventos, y no importa cuándo o dónde se crea el componente, porque siempre mostrará la información correcta. Podría usar un evento para actualizar el estado global, pero ¿por qué hacerlo cuando puede simplemente ... actualizarlo?

Un enfoque declarativo le permite escribir sus componentes de una manera que siempre aparece de la misma manera dependiendo exactamente del estado local / global, independientemente de lo que haga el usuario en su aplicación, sin tener que escuchar lo que suceden. Creo que esto es para lo que se diseñó Vue desde el principio, pero al igual que la mayoría de las cosas en el desarrollo de software, nos tomó un tiempo darnos cuenta de eso. Pero estoy muy contento de haberlo hecho.

EDITAR: Ah, y no olvide que puede observar los parámetros y, digamos, enviar una solicitud AJAX o realizar alguna otra acción cuando cambie. por ejemplo, después de que un usuario inicia sesión, observe la variable 'logIn', cuando sea verdadera, cargue sus imágenes de perfil o algo así.

Entiendo lo que estás diciendo, pero tener algún componente aleatorio que modifique el estado global es, creo, lo mismo que tener ese componente aleatorio en un evento hacia Dios sabe dónde. Aún corre el mismo riesgo de que el flujo de su aplicación "se ensucie" accidentalmente.

Hay formas de manejar ambos paradigmas de una manera limpia y eso generalmente (y debería) terminar siendo responsabilidad del usuario del framework.

Habrá ciertas situaciones en las que un mecanismo tendrá más sentido que el otro. Por ejemplo, estoy de acuerdo en que un estado de inicio de sesión debe ser algo conocido por toda su aplicación: el estado global tiene sentido. Pero el botón en el que el usuario de la aplicación hace clic generalmente no manejará la lógica detrás del registro del usuario. Eso será algo manejado más arriba en la cadena. Podría ser un componente, podría ser una ruta. Es probable que el botón solo deba notificar algo sobre la intención de iniciar sesión. Por lo tanto, el botón no necesita modificar su estado global directamente.

Entonces, ahora, con la eliminación de $ dispatch, necesita que el componente de botón conozca algún objeto global que administra la sesión de usuario de la aplicación y le notifique directamente de la intención. Esto hace que el botón esté estrechamente acoplado a toda su aplicación.

O bien, puede tener el botón anidado a 10 niveles de profundidad y tendría que declarar un controlador v-on:login en cada nivel para que la intención llegue a su destino. Totalmente innecesario.

En realidad, tener que hacer v-on en todos los niveles solo hace que su código sea más difícil de mantener.

Bueno, obviamente, cambiar directamente el estado puede ser problemático, pero Vuex resuelve ese problema con mutaciones y acciones. Y es cierto que algunas soluciones encajarán mejor que otras, pero nunca me he encontrado con una situación en la que la lógica declarativa no fuera la mejor opción.

En su caso específico, probablemente no haría un botón específico para iniciar sesión, je. En el apéndice, si un componente relacionado con el inicio de sesión está anidado tan profundo por alguna razón, simplemente mute el estado global.

El botón de inicio de sesión fue solo un ejemplo. Y una tienda vuex es a lo que me refería cuando mencioné "algún objeto global". Tendría que investigar cómo funciona vuex, pero espero que esté acoplando estrechamente algún componente aleatorio al resto del estado de su aplicación simplemente teniendo que administrar una referencia a la tienda.

Esto no es deseable si, por ejemplo, el botón de inicio de sesión formaba parte de alguna biblioteca de terceros.

Realmente desearía que no eliminara la * _ opción * _ para usar cualquiera de los paradigmas, especialmente cuando la propagación de eventos es ampliamente reconocida y, por lo tanto, fácil de comprender para los nuevos colaboradores de un proyecto.

Depende de lo que quiera decir con "algún componente aleatorio", porque un componente de vista de enrutador, por ejemplo, tiene todos los derechos para acceder y comprometerse con la tienda en mi opinión. Sin embargo, si se trata de un componente más pequeño para su reutilización, como un botón, formulario o algún otro elemento de la interfaz de usuario, 9 de cada 10 veces, no debería haber ninguna razón lógica para que acceda a la tienda, por encima del uso de accesorios y eventos.

Dado que los datos en una aplicación Vue son de arriba hacia abajo, desea mantener la mayor parte de su estado local en el nivel superior posible. El anidamiento profundo en sí mismo es un problema que debe evitarse tanto como sea posible. No es _que_ una gran molestia propagar eventos dos niveles hacia abajo, pero es probable que deba reconsiderar la estructura de su plantilla si va más allá de eso.

Sin embargo, eso es principalmente una tangente. Muchas veces, los paradigmas más fáciles de entender son los que terminan siendo abusados ​​hasta el final del infierno y se vuelven difíciles de manejar. Un enfoque basado en el estado es mucho más sencillo, según lo acordado por la mayoría de nosotros que actualmente usamos 2.0. Puede continuar usando 1.0 o pasar a otro marco si este enfoque no es de su preferencia.

9 de cada 10 veces, no debería haber ninguna razón lógica para que acceda a la tienda, por encima del uso de accesorios y eventos.

Exactamente mi punto.

El anidamiento profundo en sí mismo es un problema que debe evitarse tanto como sea posible.

A veces, esta no es una opción.

No es tan molesto propagar eventos dos niveles más abajo

No es tan cierto cuando esos niveles son más profundos.

Los paradigmas más fáciles de entender son los que terminan siendo abusados ​​hasta el final del infierno y se vuelven difíciles de manejar.

Esto debería depender de la disciplina de sus usuarios.

Puede continuar usando 1.0 o pasar a otro marco si este enfoque no es de su preferencia.

Mmk.

La simplicidad y la conveniencia es la razón por la que estaba considerando cambiar de Ember a Vue. $dispatch es una de las cosas que disfruté de Vue y eliminarlo me parece tan arbitrario.

El equipo eliminó muchas funciones para la versión 2.0. Sinceramente, estoy de acuerdo con todos ellos. Pero no este.

Gracias por tus respuestas.

@ktsn Las alternativas a $ broadcast y $ dispatch son muy simples, esta eliminación ha mejorado y mejorado.

@rhyek Me gustaría dar mi 2ct sobre un par de puntos que planteaste. Dado que la discusión ya ha abordado una serie de temas, me gustaría volver a lo básico sobre por qué desaprobamos $ diospatch y $ broacast:

1. acoplamiento implícito.

Si tiene un padre y un hijo profundamente anidado que distribuye un evento, no hay forma de inferir esta relación del código (y lo mismo es cierto para $broadcast , obviamente).

Si observa los otros cambios y depreciaciones que introdujimos con Vue 2.0, es posible que se dé cuenta de que eliminar el comportamiento implícito a favor de alternativas explícitas es un tema común, y desaprobar $dispatch encaja perfectamente allí.

Ejemplo:

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

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

Esto está bien cuando el padre solo tiene un hijo directo, pero en ese caso, $emit() con un oyente en la plantilla tampoco es un trabajo adicional real.

Se vuelve difícil de seguir (especialmente en equipos) tan pronto como tiene hijos anidados (especialmente anidados profundamente), o incluso más de un hijo directo: debe revisar todos los hijos o confiar en los comentarios del código para documentar qué evento es a partir de qué componente hijo, que también es un texto estándar adicional.

Dices que te gustan $ dispatch y $ broadcast porque no tienes que pasarlos a través de otros componentes. Y puedo estar de acuerdo en que es más fácil, pero no nos hemos encontrado con muchas situaciones en las que esto sea realmente necesario, o más bien: si hubiera tal cadena de pasar un evento, preferiría que los datos se cambiaran / adjunto / durante este viaje por componente intermedio.

2. Nombres de eventos

cuando usa $dispatch con componentes profundamente anidados, tendría que ser muy explícito en el espacio de nombres de sus eventos, porque de lo contrario, podrían estar en conflicto:

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

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

..y si esos niños son bibliotecas de terceros, estás jodido ahora. o tener que capturar el evento en algún componente en el medio solo para cambiarle el nombre antes de $dispatch() más arriba del padre. Y no olvide comentar esto, porque alguien que esté mirando este código podría pensar por qué no hace nada más con un evento que cambiarle el nombre.

El uso de $ emit y oyentes de plantillas no tiene este problema. Puedes usar nombres de eventos cortos y simples en todas partes, no chocarán ya que cada evento tiene su propia devolución de llamada adjunta en la plantilla @close="callback ".

Realmente desearía que no te quitaras la * opción * de usar cualquiera de los paradigmas,

Si pensáramos que ambos paradigmas pueden funcionar igualmente bien, los trataríamos por igual. Pero no pensamos eso, por las razones anteriores y más.

Por lo tanto, tratamos de guiar a los usuarios hacia los pactos que encontramos que funcionan mejor, dejando una forma de evitarlo con el método del "bus global".

También me gustaría hablar sobre sus preocupaciones sobre el estado global, pero aún no estoy seguro de haber entendido completamente su posición.

Tal vez pueda proporcionar un ejemplo en el que crea que $ dispatch y $ broadcast funcionan mejor para usted, y yo trato de mostrarle cómo "nuestro" enfoque podría mejorar la situación.

Creo que $ dispatch / $ broadcast y event bus abordan cosas diferentes. Pueden hacer que el código sea fácil de mantener y desacoplado en diferentes escenarios. Si podemos mantenerlos a ambos, será genial.
Es muy difícil decir que uno es mejor que otro en todos los casos.

@cnweibo Creo que ha habido argumentos bastante exhaustivos en ambos lados y, sinceramente, no veo su punto de "abordar cosas diferentes". Siéntase libre de presentar más argumentos, pero puedo decirle con certeza que esto no sucederá.

Si realmente lo desea, no es tan difícil implementarlo usted mismo como complemento.

@LinusBorg Realmente aprecio el tiempo que se tomó para escribir su respuesta y comprendo sus argumentos.

Dices que te gustan $ dispatch y $ broadcast

Sinceramente, me gusta $dispatch . $broadcast definitivamente me pareció extraño. Como dije, $dispatch es solo un evento burbujeante, que es algo omnipresente entre muchas plataformas en este momento. $broadcast ... no tanto. Lo único similar que he encontrado son los eventos de "vista previa" en WPF que están emparejados con eventos normales. Ellos "hacen un túnel" por el árbol visual desde el elemento más alto hasta la fuente del evento original, pero solo se envían directamente hacia abajo en la cadena de elementos relacionados y no se _spande_ a todo.

tendrías que ser muy explícito en el espacio de nombres de tus eventos

Estoy de acuerdo con eso y normalmente es lo que hago, de todos modos. También es lo que la gente está acostumbrada a hacer en jQuery. Además, algunas plataformas simplemente envían un objeto "fuente" como argumento al controlador y tal vez podría filtrar contextos basándose en eso (pista: instanceof ). Los eventos DOM tienen event.target disponibles, por ejemplo. Otras plataformas tienen la ventaja de trabajar con tipos estáticos, por lo que este "choque" es bastante difícil de encontrar (un evento es una instancia de una clase).

En cualquier caso, honestamente, no entiendo por qué esto es una preocupación para el equipo de VueJS. Si la gente no puede ser lo suficientemente cuidadosa al usar $dispatch , estoy seguro de que puede encontrar muchas otras cosas que están haciendo mal usando su biblioteca. ¿Hasta dónde llegará para "proteger" a sus usuarios de ser descuidados?

Esto está bien cuando el padre solo tiene un hijo directo, pero en ese caso, $ emit () con un oyente en la plantilla tampoco es un trabajo adicional real.

Pregunta honesta (ya que soy decididamente nuevo en Vue), además de declarar oyentes en todos los niveles, ¿no tienes que $emit el evento en cada componente de la cadena? Eso parece muy molesto.

En conclusión, permítanme citar algo que alguien dijo sobre un problema en vue-cli sobre la introducción de "plantillas oficiales" para nuevos proyectos (https://github.com/vuejs/vue-cli/issues/123#issuecomment-233071630):

Como probablemente sepa, no está limitado a las plantillas oficiales. Esto te da libertad pero al mismo tiempo hace que necesites tomar más decisiones tú mismo.

Creo que al final todo es solo un metro de equilibrio. ¿Cuántas de estas decisiones podemos tomar por adelantado para todos (la mayoría) de nuestros usuarios y cuántas o cuáles los usuarios quieren tomar por su cuenta?

Estoy de acuerdo con esa filosofía, pero extrañamente no es la misma actitud que he encontrado sobre este tema. El contraste que veo entre ese comentario y los comentarios aquí se reduce a la libertad. Estás eliminando opciones basadas en intenciones, aunque buenas, en última instancia defectuosas.

Si realmente lo desea, no es tan difícil implementarlo usted mismo como complemento.

@ yyx990803 Eso es probablemente lo que _ terminaré_ haciendo ... probablemente.

@LinusBorg también:

Por lo tanto, tratamos de guiar a los usuarios hacia los pactos que encontramos que funcionan mejor, dejando una forma de evitarlo con el método del "bus global".

No estás "tratando de conducir", estás forzando. :)

¿Ha intentado implementar la misma función con los métodos dispatch y EventBus?
Puede ayudar

@posva Planeo, pero quiero decir, básicamente declaras el objeto bus de eventos en algún módulo, y lo importas donde quieras $emit , ¿no? No me gusta eso, tbh. Definitivamente lo usaré para algunas cosas, pero creo firmemente que no es lo que quiero hacer siempre.

En cualquier caso, honestamente, no entiendo por qué esto es una preocupación para el equipo de VueJS. Si la gente no puede ser lo suficientemente cuidadosa al usar $dispatch ,

Bueno, el punto es que nadie en el equipo pudo señalar un caso de uso de la vida real para $dispatch() en el que fuera preferible a otras soluciones (no solo $emit() , sino también un autobús, o estado global), y tampoco vimos ninguno en las innumerables publicaciones del foro al respecto que respondimos.

Esta puede ser una visión subjetiva, pero tal vez puedas entender que si todo el equipo piensa que "esto es, en nuestra experiencia, siempre una solución inferior", lo descartamos desde el núcleo.

En este punto, quiero renovar mi oferta para discutir un ejemplo real.

Estoy seguro de que puede encontrar muchas otras cosas que están haciendo mal usando su biblioteca. ¿Hasta dónde llegará para "proteger" a sus usuarios de ser descuidados?

Esta es, por supuesto, una cuestión delicada y un equilibrio difícil de encontrar. Tendremos que juzgar caso por caso.

Esto está bien cuando el padre solo tiene un hijo directo, pero en ese caso, $ emit () con un oyente en la plantilla tampoco es un trabajo adicional real.

Pregunta honesta (ya que soy decididamente nuevo en Vue), además de declarar oyentes en todos los niveles, ¿no tienes que $ emitir el evento en cada componente de la cadena? Eso parece muy molesto.

Dado que hablo de las liberaciones directas entre padres e hijos, solo tendrías que $ emit () una vez.

Si tiene hijos profundamente anidados, por supuesto, tiene que volver a emitir en todos los niveles, pero repito: no hemos encontrado ni se han presentado situaciones que se estén enviando a través de muchos hijos anidados es realmente necesario o preferible a otras soluciones.

Por lo tanto, tratamos de guiar a los usuarios hacia los pactos que encontramos que funcionan mejor, dejando una forma de evitarlo con el método del "bus global".

No estás "tratando de conducir", estás forzando. :)

Yo diría que hacemos tu vida un poco más difícil, puedes

  • utilizar un bus, que no es lo mismo pero puede lograr un comportamiento similar en la mayoría de los casos.
  • Vuelva a implementar esto como un complemento con bastante facilidad.

No lo estamos obligando a usar $emit() , solo estamos haciendo que su camino sea un poco más difícil.

Creo que también puede agregarlo a cada instancia de Vue: Vue.prototype.$bus = new Vue()
No gustarle algo no es muy constructivo ...
Estaré esperando tus ejemplos 😄

@posva

Creo que también puede agregarlo a cada instancia de Vue: Vue.prototype. $ Bus = new Vue ()

Me gusta eso. Muy inteligente.

No gustarle algo no es muy constructivo

Creo que ese es un criterio bastante válido para elegir usar algo o no, al menos para mí. En cualquier caso, he dicho muchas veces por qué creo que el burbujeo de eventos tiene su lugar.

Estaré esperando tus ejemplos 😄

Quiero decir, ¿realmente lo necesito? He dado ejemplos sobre situaciones en las que no me gusta la idea de usar un bus de eventos o declarar oyentes en todos los niveles. ¿Quieres ver el código? Quizás se me ocurra algo para aclarar un poco mi punto, pero creo que el burbujeo de eventos es algo bastante estándar que la mayoría de la gente puede apreciar como algo útil, y los autobuses de eventos o los administradores estatales son, al menos para mí, una especie de cambio de paradigma que, aunque no es difícil de comprender en absoluto, parece territorio hipster. 😄

Por supuesto que estoy bromeando sobre ese último comentario. Como dije antes, veo sus usos y definitivamente encontraré un problema para resolver con ellos. De hecho, en algunos proyectos en los que he trabajado usando Ember, tiendo a escribir un "servicio" que actúa exactamente como un administrador de estado global. Te lo aseguro, no estoy tratando de ser terco sobre esto a propósito.

Realmente me gusta Vue. Solo quiero _ amarlo_, ¿sabes?

¿No tienes que también $ emitir el evento en cada componente?

Lo hace si piensa en términos de eventos burbujeantes. Y no lo hace si usa composición de componentes.

P.ej:

<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 componente a-button , porque tanto a-modal como dos instancias a-button son "hijos lógicos directos" de una única instancia , a pesar de tener una jerarquía de vistas complicada con el anidamiento.

Creo que me estoy repitiendo en este punto. Terminaré resolviendo este problema, de alguna manera. Me parece extraño que esta discusión haya girado en torno a establecer varias soluciones para algo bastante estándar y práctico que simplemente ya no existe por alguna razón.

@LinusBorg :

Bueno, el punto es que nadie en el equipo pudo señalar un caso de uso de la vida real para $ dispatch () en el que era preferible a otras soluciones (no solo $ emit ()

Esto me suena a un ingeniero civil que me pregunta por una razón para no cerrar una salida de la autopista:

Dice algo como: "Esta rampa de salida conduce a una intersección donde la gente se confunde sobre si girar a la izquierda o a la derecha. La mayoría de la gente conoce el camino porque ha vivido aquí durante años, pero los nuevos ciudadanos a menudo se pierden por un par de minutos y queremos evitar eso ".

Le digo: "Está bien, claro, puedes cerrarlo, está bien. Tendré que viajar 10 km más hasta la siguiente rampa de salida. Me las arreglaré".

:) Gracias por sus respuestas a todos. Me alegro de que estén abiertos a la discusión, al menos. Parece un buen equipo.

Esto me suena a un ingeniero civil que me pregunta por una razón para no cerrar una salida de la autopista:

Dice algo como: "Esta rampa de salida conduce a una intersección donde la gente se confunde sobre si girar a la izquierda o a la derecha. La mayoría de la gente conoce el camino porque ha vivido aquí durante años, pero los nuevos ciudadanos a menudo se pierden por un par de minutos y queremos evitar eso ".

También agregaré mi mala metáfora. :) En mi opinión, es más como:

  • "Esta carretera anima a las personas a correr más rápido de lo que deberían. Rara vez se presta atención a los límites de velocidad. Deberíamos añadir algunos parachoques para obligar a las personas a reducir la velocidad".
  • "¡Pero me gusta llegar a mi destino rápidamente acelerando!"
  • "Seguro, podría servirle bien algunas veces, pero observamos esta parte de la carretera constantemente durante más de 1,5 años, y la cantidad de accidentes y personas que se pierden la siguiente rampa de salida simplemente no vale la pena, ya que muchos conductores que han tenido uno de esos problemas ha atestiguado ".
  • "¡Pero no me gustan esos parachoques!"
  • Bueno, para el 99% de los destinos, esta otra carretera es tan rápida como esta antes de los parachoques, solo toma esta.
  • "¡Pero no me gusta este otro camino! ¡La vista no es tan agradable!"
  • ...

No gustarle algo no es muy constructivo

Creo que ese es un criterio bastante válido para elegir usar algo o no, al menos para mí. En cualquier caso, he dicho muchas veces por qué creo que el burbujeo de eventos tiene su lugar.

Creo que @posva quiso decir: "Me gusta esto" no es un argumento constructivo cuando se habla de si guardar algo o agregar algo a la biblioteca con una amplia gama de usuarios. Es por eso que sigo pidiendo un caso de uso válido y de la vida real para discutir en lugar de preferencias personales.

Sí, excepto que hiciste volar la carretera en perfecto estado y construiste otra con asfalto recubierto de goma porque leíste en algún lugar que está bastante limpio. Además, son 10 km adicionales. :)

Sobre el ejemplo: Creo que el que se publicó en la pregunta original sobre componentes recursivos está bien. Solo imagina que quieres hacer algo en todos los niveles en secuencia cuando se detecta un evento y tienes un ejemplo perfectamente bueno. Hacer eso con $ dispatch es bastante sencillo.

¿Quieres ver el código?

Sí, por favor

@posva di un ejemplo sobre el comentario anterior. Nota: si tienes que pensar más de unos segundos en cómo hacerlo sin $ dispatch, eso prueba mi punto.

Sobre el ejemplo: Creo que el que se publicó en la pregunta original sobre componentes recursivos está bien. Solo imagina que quieres hacer algo en todos los niveles en secuencia cuando se detecta un evento y tienes un ejemplo perfectamente bueno. Hacer eso con $ dispatch es bastante sencillo.

con $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>

con $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>

¿Eso es realmente peor?

¿Tienes otro? :)

Claro. ¿Qué pasa si no son recursivos pero aún así anidados?

Bien. Son las 5 de la mañana aquí y voy a tener un día difícil gracias a ti. Si se me ocurre algo mejor más tarde, lo publicaré si no, entonces, o ganaste o perdí el interés :)

¿Qué pasa si no son recursivos pero aún así anidados?

Tendría que agregar un @event= oyente en cada plantilla por $emit() , y no así por $dispatch() , eso es todo.

Esto puede verse como bueno o malo, dependiendo de si enfatiza la verbosidad o la expresividad.

y por cierto. si en una situación tiene que encadenar un evento hasta que el padre, esto se puede hacer de la siguiente manera:

<child-comp @event="$emit('event', $arguments)>
  • Lamentarás el "acoplamiento" que esto hace entre los componentes.
  • Alabaré la expresividad
  • Aparte de eso, es un poco más de escribir, pero no es gran cosa.
  • y sigo afirmando, con un ejemplo de caso de uso real, que probablemente haya una optimización diferente disponible, como una tienda global, pero eso depende del escenario individual y es difícil discutir con el código de ejemplo.

De todos modos, buena discusión, disfruta de tu merecido sueño.

@rhyek parece una solución alternativa solo porque ha decidido usar $dispatch en primer lugar, pero ese no es el objetivo. El objetivo es permitir que los componentes se comuniquen entre sí con un mantenimiento decente. Al lograr ese objetivo, $dispatch es la solución inferior cuando enumera todos los pros y los contras prácticos, excluyendo las preferencias, por lo que la descartamos.

También tenga en cuenta que la propagación de eventos DOM es fundamentalmente diferente de la comunicación entre componentes. El argumento de que "el burbujeo de eventos es ampliamente reconocido" no significa que deba ser una buena solución para el problema que estamos tratando de resolver.

Terminé de comentar en este hilo porque me resulta difícil discutir con "Simplemente no me gusta".

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

aviggngyv picture aviggngyv  ·  3Comentarios

robertleeplummerjr picture robertleeplummerjr  ·  3Comentarios

loki0609 picture loki0609  ·  3Comentarios

julianxhokaxhiu picture julianxhokaxhiu  ·  3Comentarios

bfis picture bfis  ·  3Comentarios