Vue: Espere ganchos de ciclo de vida de componentes asíncronos

Creado en 8 dic. 2017  ·  51Comentarios  ·  Fuente: vuejs/vue

¿Qué problema resuelve esta función?

Si un usuario necesita implementar un gancho de ciclo de vida que depende de operaciones asíncronas, vue debe respetar la naturaleza asíncrona del gancho implementado y esperarlo en vue land.

¿Cómo se ve la API propuesta?

La API no cambia; solo cómo funciona ahora esperando los ganchos asíncronos.

Comentario más útil

Este es el código real que quiero que me esperen:

  beforeMount: async function() {
       this.user = await client.get({type: 'user', id: this.$route.params.id});
    }

Que sería parte del componente UserPage .

Todos 51 comentarios

Entonces quieres

created () {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('created')
            resolve()
        })
    })
},
mounted () {
    console.log('mounted')
}

para mostrar

mounted

?

Al crear una solicitud de función, agregue un caso de uso del mundo real para que valga la pena implementar la solicitud.

Si bien esta es teóricamente una idea genial, esto requiere un replanteamiento / reescritura fundamental de la arquitectura para lograrlo y, potencialmente, puede romper mucha lógica que se basa en la naturaleza sincrónica de los ganchos del ciclo de vida. Por lo tanto, los beneficios deben ser sustanciales para justificar ese cambio; de lo contrario, esto solo se puede considerar cuando planeemos hacer una actualización completa, lo que es poco probable que suceda muy pronto.

Cerrando por ahora, pero siéntase libre de hacer un seguimiento con razonamientos / casos de uso / implicaciones más concretos.

@posva Entendido, me disculpo. Mi caso de uso real es uno en el que tengo un componente UserPage que recibe un user_id de los parámetros de ruta de la página (a través de this.$route.params ), luego recupera los datos reales del usuario de la base de datos en el servidor usando un comando como:
this.user = await client.get({type: 'user', id: this.$route.params.id})
donde this.user refiere a un campo user en la parte data del componente UserPage .

Idealmente, quiero que esa línea de código se ejecute después de que se haya creado el componente (para que this.$route.params esté disponible) pero antes de que el componente esté realmente montado para que en mi plantilla pueda usar de forma segura user interpolaciones sin obtener ningún error sobre valores indefinidos.

@ yyx990803
Podría ser un novato aquí, pero ¿no debería el único cambio agregar la palabra clave await antes de la llamada a los ganchos del ciclo de vida como mounted , etc., en Vue Land?

Este es el código real que quiero que me esperen:

  beforeMount: async function() {
       this.user = await client.get({type: 'user', id: this.$route.params.id});
    }

Que sería parte del componente UserPage .

¡No hay problema! Me estaba imaginando ese caso de uso. Es mejor manejarlo como se describe en los documentos de vue-router, ya que abre diferentes formas de mostrar el estado de carga. Ya puede esperar a que los datos estén allí antes de renderizar el componente por cierto.

Está bien, eso tiene sentido. Ahora, sin embargo, ¿qué pasa si tengo un componente de usuario que es una versión simplificada de la página de usuario (digamos, como el componente que aparece cuando pasas el cursor sobre el nombre de un usuario en Facebook y "echas un vistazo" en su perfil), entonces el enrutador no está involucrado aquí y id pasará como una propiedad al componente.

Tomando el panorama general aquí, las funciones en JavaScript ahora pueden ser síncronas o asincrónicas, y que los enlaces del ciclo de vida sean funciones, y la forma en que las consideramos funciones, deberían admitir la asincronía (como lo demuestra mi caso de uso y mi "alcance" intuitivo para el enfoque que estoy usando aquí).

Tienes muchas formas de hacerlo. El más simple es usar una variable que comienza como nula, obtener los datos y configurarlos, alternando el componente real (debido a un v-if). Una versión más exótica sería una función que resuelve el componente y usa <component :is="myDynamicComp"/> 😄
Pero, por favor, no confunda el problema en una pregunta 😉 use el foro o la discordia para eso

¡No, realmente no quiero ayuda con el código! En realidad, ya he implementado soluciones alternativas muy similares a sus sugerencias. Lo que estoy tratando de decir es que es mucho más intuitivo usar las funciones asíncronas de JS.

La parte de la que no me di cuenta es que el código asíncrono y el síncrono son fundamentalmente diferentes por naturaleza, por lo que no se puede obligar al código síncrono a adherirse al código asíncrono sin cambiar fundamentalmente a sí mismo a código asíncrono. yyx990803 lo vi de inmediato, pero me tomó un tiempo entender completamente su comentario. Gracias por su tiempo chicos y perdón si hubo una falta de comunicación de mi parte en algún lugar del camino.

Tengo un caso de uso aquí y me gustaría obtener alguna sugerencia y un método alternativo.

MainPage.vue es mi contenedor principal. Llamo a ajax "/ init" en beforeCreate para obtener información del usuario y luego me comprometo con Vuex.store.
Content.vue es el niño dentro de MainPage.vue . Me gustaría llamar a diferentes llamadas de API en mounted stage de acuerdo con el rol del usuario que provienen de Vuex.store.

Si el ciclo de vida llama en async / await flow, seguiría el orden
Parent beforeCreate -> Parent create -> Child beforeCreate -> Child create -> Child montado .... (Si entiendo correctamente sobre el ciclo de vida del componente).

Pero actualmente no puedo obtener información de usuario en Content.vue , ¿cómo puedo solucionarlo ahora?
Me gustaría mantener la api "/ init" llamada dentro de MainPage.vue porque se usa en muchas páginas (contenedor en Vue-Router).

pregunta publicada en stackoverflow

Gracias

una solución hackish para lo que vale la pena:

{
  created: function(){
    this.waitData = asyncCall();
  },
  mounted: function(){
    this.waitData.then(function(data) { ... })
  }
}


Una posible solución más "plana":

{
    async created () {
        let createdResolve = null
        let createdReject = null
        this.createdPromise = new Promise(function(resolve, reject){
            createdResolve = resolve
            createdReject = reject
        })
        await asyncCall1()
        await asyncCall2()
        ...
        createdResolve(someResult)
    }
    async mounted () {
        let result = await this.createdPromise
        ...
    }
    data () {
        return {
            createdPromise: null
        }
    }
}

¿No es esto todavía una cosa?

data() {
 ...
},
async created() {
  const something = await exampleMethod();
  console.log(something);
}

Funciona para mí (como menciona

@breadadams Sí, por supuesto. Se esperarán las funciones _dentro_ del método created ; sin embargo, la función created o mounted sí no lo es.

Entonces, la instancia de Vue llamará created e instantáneamente mounted antes de que finalice cualquiera de los procesos de larga ejecución en created

Ah , mi mal @ darren-dev - caso de uso diferente de mi lado, pero veo el problema ahora 😅 gracias por aclarar.

@breadadams No hay problema en absoluto, estamos todos aquí para nuestros propios casos, ¡me alegro de poder aclarar!

El enlace del ciclo de vida asíncrono puede ser una buena implementación en la próxima versión principal

Me parece que permitir el soporte asíncrono para los métodos del ciclo de vida fomentará las malas prácticas de UX de forma predeterminada. ¿Cómo? Las funciones asíncronas se utilizan para solicitudes que no se pueden completar inmediatamente (por ejemplo, solicitudes de red o de larga duración). Obligar a Vue a retrasar la creación o el montaje o cualquiera de los otros métodos del ciclo de vida para esperar su solicitud de red o un proceso asíncrono de larga ejecución afectará al usuario de manera notable. Imagine que un usuario llega a su sitio y luego tiene que esperar 4 segundos con una pantalla en blanco mientras el componente espera a que la conexión celular irregular del usuario finalice su solicitud de red. Y esto no solo tiene un impacto negativo en el usuario, sino que también está sacrificando su control sobre la situación; no hay nada que pueda hacer como desarrollador para que los usuarios perciban el tiempo de carga más rápido o muestren indicadores de progreso determinados o indeterminados. Por lo tanto, al incorporar esta capacidad en Vue, no está haciendo de la web un lugar mejor; estás habilitando malas prácticas.

Es mucho mejor planificar y diseñar para el caso asincrónico desde el principio: inicie su proceso asincrónico en created o mounted o donde sea, y luego haga que su componente tenga una estructura esquelética o en el peor de los casos una ruleta mientras espera que su API devuelva los permisos del usuario. Mucho mejor UX y no sacrificas ningún control. Y Vue no tiene que agregar código para lidiar con las funciones asincrónicas del ciclo de vida, lo que hace que el paquete sea más pequeño. Gana, gana.

@seanfisher Plantea un punto válido. Desde el punto de vista arquitectónico, el desarrollador debe manejar el diseño en torno a un conjunto asincrónico de eventos, ya que esa es la única forma de representar el mensaje correctamente.

Descargo de responsabilidad : Lo siguiente está escrito teniendo en cuenta la idea de la generación de páginas. Definitivamente hay casos de uso válidos en los que mi argumento no es válido.


Sin embargo, dictar los patrones de diseño de un desarrollador no debe dejarse en manos del marco que está utilizando. Mi argumento es que si no está esperando a que se complete una fase, ¿por qué tener diferentes fases? ¿Por qué tener un escenario creado y luego montado? Si todo está sucediendo básicamente a la vez, entonces ignorar por completo la etapa creada está bien.

Literalmente, la única vez que (desde el comienzo de Vue) me enganché a crear fue cuando tuve que inyectar algo en lo que vue necesitaba confiar; no tenía nada que ver con la configuración o el diseño de mi página. Sin embargo, tuve que esperar a que se ejecutaran tareas asíncronas (cortas) que serían mucho mejores _antes_ de que la página se renderizara (como conectarse a los métodos de autenticación de Firebase). Tener eso en crear, luego esperar a que se complete antes de montarlo reduciría la necesidad de soluciones hacky completamente.

Recuerde, mi argumento es que Vue no debería decirme que me estoy desarrollando mal. Solo debería proporcionar la funcionalidad deseada.

Sin embargo, dictar los patrones de diseño de un desarrollador no debe dejarse en manos del marco que está utilizando.

Um ... Los marcos se construyen para limitar, guiar o "enmarcar" específicamente al desarrollador en ciertos patrones y prácticas de diseño. Ese es su principal propósito. Cualquier buen marco ofrecerá una API inteligente, que ofrece precisamente una forma clara y obvia de trabajar con el marco y, sin embargo, también será restrictiva.

Sí, es paradójico que un framework ofrezca ciertas habilidades, pero también restrinja al desarrollador al mismo tiempo a ciertas prácticas de diseño. Ahí es exactamente donde la opinión dentro de Frameworks puede ayudarlo o dañarlo. Es difícil encontrar el equilibrio adecuado y creo que Vue, o más bien Evan y el equipo de desarrollo de Vue, han hecho y están haciendo un gran trabajo tomando estas decisiones.

Scott

Nunca diré que un marco bien diseñado debería extenderse con el mismo patrón de diseño, pero mi argumento es que el marco no puede dictarlo. Tienes razón, pero estoy diciendo que no importa qué tan bueno sea el marco, el desarrollador final aún debería estar abierto para hacer lo que quiera.

Pero no ha tocado el argumento _actual_ de hacer que los eventos creados y montados sean asíncronos; acaba de agregar su opinión (que no es incorrecta) a mi opinión, lo que generalmente conduce a un gran descarrilamiento.

Nunca diré que un marco bien diseñado debería extenderse con el mismo patrón de diseño, pero mi argumento es que el marco no puede dictarlo.

Lo siento, pero esto no tiene sentido para mí. Por favor muéstreme un marco que no dicta cómo debe extenderse.

Pensé que decir "Evan y compañía tomando buenas decisiones" mostraría mi opinión. Pero, para ser más claro. Los enlaces de ciclo de vida montados y creados no necesitan funcionar de forma asincrónica o, más bien, el hecho de que funcionen de forma sincrónica ayuda a razonar sobre la lógica de la aplicación. Cualquier "espera" debe tenerse en cuenta en la interfaz de usuario de todos modos y aún se puede ejecutar código asincrónico en cada enlace. Podemos discutir sobre lo necesario ahora que son los ganchos beforeMount y mount. Pero, puede haber una cosa o dos que pueda necesitar en montado, por ejemplo, a las que aún no puede acceder en creado, como la función de renderización compilada.

Scott

Si Vue tiene una opinión de una forma u otra sobre los ganchos del ciclo de vida asíncrono, no debería ser una cuestión de especulación. No hay necesidad de especular cuando los estándares, API, guías y mejores prácticas que Vue adopta, proporciona o recomienda están disponibles para que todos los lean.

En la respuesta original de Evan, los ganchos del ciclo de vida asíncrono no están en la API estándar no porque sea necesariamente una mala idea, sino porque los beneficios no son lo suficientemente sustanciales como para justificar el costo de implementación.

Para la opinión de que es una mala práctica hacer que el usuario espere un created asíncrono u otro gancho del ciclo de vida sin un indicador de que algo está sucediendo, se puede argumentar que Vue, habiendo admitido los ganchos asíncronos, ahora tal vez proporciona algo que podría denominarse "plantillas de fase" que también resolvería el problema (y que podría ser fácil de implementar).

Para la opinión de que es una mala práctica hacer que el usuario espere a que se cree un async u otro gancho del ciclo de vida sin un indicador de que algo está sucediendo,

¿Es esto realmente un problema?

Scott

Este es el problema que tengo, y tal vez alguien pueda sugerir cómo DEBO estar haciendo esto porque parece problemático.

Nuestra aplicación Vue (bastante grande) utiliza Vuex de forma extensiva. En bastantes de nuestros componentes de Vue en el ciclo de vida create (), configuramos a través de store.dispatch () algunos elementos de la tienda (obviamente). Sin embargo, como me ha llamado la atención, store.dispatch () SIEMPRE devuelve una promesa ... incluso si la lógica y la función subyacentes NO son asíncronas. Así que puse async created () {await store.dispatch ('foo / action')} pero como se señaló, en realidad falla ..

También estoy usando TypeScript y se queja bastante amargamente cuando no espero / .entonces las llamadas store.dispatch () ... tienen promesas "flotantes" ...

Entonces, ¿cuál es la mejor manera de usar Vuex store.dispatch () en un ciclo de vida cuando no podemos sincronizarlos?

¡¡Salud!!

Cualquier otra discusión sobre las opiniones específicas de vue, y si los marcos deberían imponer opiniones a un lado, podría ser beneficioso documentar este comportamiento con mayor claridad.

Estoy viendo la solución "más plana" de mounted() regrese. En esa solución, tanto created() como mounted() son asíncronos, por lo que Vue llamará a cada uno de ellos y regresarán más o menos inmediatamente, con las cosas asíncronas en segundo plano. De hecho, no estoy seguro de cómo eso es mejor que simplemente eliminar el createdPromise y simplemente hacer todo el trabajo asíncrono en created() o mounted() , como:

async mounted() {
  let response = await fetch(my_url)
  let data = await response.text()
  my_data_member = data
}

En cualquier caso, my_data_member se completará "más tarde" cuando se complete el XHR, mucho después de que mounted() devuelva su Promesa, ¿verdad?

También puede intentar usar v-if en el componente raíz <div id="app"/> y activarlo cuando finalice la carga de datos. Yo, por ejemplo, lo uso como token de actualización.

Esta es una característica interesante y tiene muchos casos de uso. Para mi caso de uso, necesito cargar propiedades específicas de la API antes del procesamiento real del componente. Sin embargo, no creo que async en los ganchos del ciclo de vida sea una solución ideal.

Actualmente, todos mencionan aquí un escenario perfecto donde las funciones asíncronas se ejecutan sin problemas. Pero digamos, por ejemplo, si la conexión de los usuarios es lenta o está retrasada y esperamos a que el componente se monte después de la respuesta de una API, entonces se distribuye todo el ciclo de vida del componente. No podremos mostrar la información de carga al usuario. O peor aún, si la API agota el tiempo de espera o devuelve un error, la aplicación se bloqueará sin montarse.

Aunque esta es una característica interesante, sugeriría que sea manejada por la aplicación en lugar del marco porque la implementación de la lógica del dominio tiene más información sobre la lógica subyacente que el marco, lo que crea menos efectos secundarios.

+1 para esta función.
Tengo un mixin utilizado por varios componentes, el mixin obtiene datos de una base de datos en el gancho montado.
Los componentes tienen que trabajar con los datos obtenidos por el mixin también en el gancho montado.
Como está ahora, tuve que implementar una devolución de llamada para ser llamado cuando el mixin haya terminado de cargar los datos y deshacerse del gancho montado en el componente.
Funciona, pero sería más bonito si el gancho montado se encargara de las promesas.

@cederron simplemente por interés, ¿por qué no puede descargar los datos en el componente principal y pasarlos como un accesorio? use un v-if para mostrar un indicador de carga mientras se cargan los datos y cuando los datos aparezcan, puede mostrar el componente, y cuando se cree, tendrá todos los datos que necesita.

Evita que el componente represente dos estados distintos no relacionados ('sin datos cargados, esperando' y 'datos cargados, puede manipularlos')

Si necesita reutilizar la lógica en varios lugares, incluso podría mover la lógica de descarga a Vuex, tiene sentido, ya que la descarga de datos iría en una acción de Vuex en lugar de un componente.

@ReinisV Creo que simplifiqué demasiado mi caso, el componente crea nuevos datos a partir de los datos obtenidos por el gancho montado en mixin, y la vista del componente está vinculada a estos nuevos datos.
Entonces, el mixin tiene que buscar datos de la base de datos> el componente crea datos a partir de él> ahora se muestra el componente

AFAIK, esto no funcionará:

export const MyMixin = {
    data: function () {
        return {
            dbData: null
        }
    },
   mounted:  async function () {
      this.dbData = await asyncFetchDataFromDB()
   }
}


export const MyComponent = {
    mixins: [MyMixin],
    data: function () {
        return {
            newData: null
        }
    },
   mounted:  function () {
      this.newData = handleDBData(this.dbData)
   }
}

dbData será nulo en el gancho de montaje del componente.

Actualmente ejecuto una devolución de llamada cuando el mixin recupera los datos, pero sería más bonito simplemente hacer que la función de montaje sea asincrónica.

No puedo decir mucho sobre vuex porque no lo estoy usando

Realmente quiero reiterar lo que @seanfisher mencionó aquí. Tener vue wait en componentes que se han marcado como async no solo causa problemas a los usuarios, el patrón de usar async / await para iniciar la búsqueda de datos está presente en todas partes. Obligaría a convertir explícitamente el código en estos enlaces del ciclo de vida en promesas no esperadas para evitar explícitamente el bloqueo de vue. En algunos casos, podría ser bueno, y si se introdujera una función, tendría que sugerir ejecutar dos ciclos de vida al mismo tiempo, el actual que maneja la ejecución de los ganchos de componentes y el otro que espera esas ejecuciones para devoluciones de llamada globales.

Pero realmente me decepcionaría reescribir literalmente cada uno de los ganchos de mi ciclo de vida para evitar bloquear vue, async/await es mucho más limpio, por lo que no usamos promesas. Cambiar esto de una manera no compatible con versiones anteriores cambia el pozo del éxito (ciclo de vida del componente no esperado) por un pozo de falla.

Es mucho mejor planificar y diseñar para el caso asincrónico desde el principio: inicie su proceso asincrónico en created o mounted o donde sea, y luego haga que su componente tenga una estructura esquelética o en el peor de los casos una ruleta mientras espera que su API devuelva los permisos del usuario. Mucho mejor UX y no sacrificas ningún control. Y Vue no tiene que agregar código para lidiar con las funciones asincrónicas del ciclo de vida, lo que hace que el paquete sea más pequeño. Gana, gana.

@seanfisher ¡ Gracias, esto es muy útil!

¿Por qué no utilizar un componente asincrónico en su lugar, que se procesará solo cuando se hayan devuelto las llamadas asincrónicas?
más información sobre la API aquí
https://vuejs.org/v2/guide/components-dynamic-async.html#Async -Components

new Vue({
  components: {
    root: () => ({ // Aync component
      // The component to load (should be a Promise)
      component: new Promise(async function (resolve) {
        await FetchMyVariables()
        resolve(MyComponent) // MyComponent will be rendered only when FetchMyVariables has returned
      }),
      // A component to use while the async component is loading
      loading: { render: (h) => h('div', 'loading') }, 
    })
  },
  render: h => h('root')
})

Si bien la mayoría de estas soluciones parecen estar bien, creo que esta es una de las principales piezas faltantes de Vue que lo hacen tan intuitivo. Creo que Vue 3 necesita implementar esto, ya que hemos llegado al punto en el que usar async await ahora es algo cotidiano. ASÍ QUE POR FAVOR @ yyx990803 Tú, vamos a tenerlo en Vue 3. POR FAVOR. Toda la arquitectura de VUE se hizo sin asumir estos casos y la mayoría de las cosas que la gente publica aquí son solo soluciones y trucos. Creo que los ganchos deberían respetar las funciones asíncronas y también esperar valores de retorno que luego se pasen a la siguiente función de gancho.

Voy a refactorizar mi código viendo que esto no está siendo respetado, pero un código feo saldrá de él ya que sería un truco.

Me parece que permitir el soporte asíncrono para los métodos del ciclo de vida fomentará las malas prácticas de UX de forma predeterminada. ¿Cómo? Las funciones asíncronas se utilizan para solicitudes que no se pueden completar inmediatamente (por ejemplo, solicitudes de red o de larga duración). Obligar a Vue a retrasar la creación o el montaje o cualquiera de los otros métodos del ciclo de vida para esperar su solicitud de red o un proceso asíncrono de larga ejecución afectará al usuario de manera notable. Imagine que un usuario llega a su sitio y luego tiene que esperar 4 segundos con una pantalla en blanco mientras el componente espera a que la conexión celular irregular del usuario finalice su solicitud de red. Y esto no solo tiene un impacto negativo en el usuario, sino que también está sacrificando su control sobre la situación; no hay nada que pueda hacer como desarrollador para que los usuarios perciban el tiempo de carga más rápido o muestren indicadores de progreso determinados o indeterminados. Por lo tanto, al incorporar esta capacidad en Vue, no está haciendo de la web un lugar mejor; estás habilitando malas prácticas.

Es mucho mejor planificar y diseñar para el caso asincrónico desde el principio: inicie su proceso asincrónico en created o mounted o donde sea, y luego haga que su componente tenga una estructura esquelética o en el peor de los casos una ruleta mientras espera que su API devuelva los permisos del usuario. Mucho mejor UX y no sacrificas ningún control. Y Vue no tiene que agregar código para lidiar con las funciones asincrónicas del ciclo de vida, lo que hace que el paquete sea más pequeño. Gana, gana.

Una opinión de miles. El hecho de que no pueda imaginar un escenario en el que la representación de componentes que se retrasa pueda convivir con una experiencia de usuario positiva no significa que no exista.

Si un marco lucha contra el desarrollador, el desarrollador encontrará otro marco.

@ robob4him

Una opinión de miles. El hecho de que no pueda imaginar un escenario en el que la representación de componentes que se retrasa pueda convivir con una experiencia de usuario positiva no significa que no exista.

Si un marco lucha contra el desarrollador, el desarrollador encontrará otro marco.

Tiene toda la razón, pero nada de lo que compartió aquí es un argumento válido para resolver el problema de una forma u otra. Ha introducido una táctica atemorizante para obligar a la comunidad a desarrollar una función. No es una continuación constructiva de la conversación.

@wparad , es absolutamente una táctica atemorizante, pero no va a obligar a nadie a hacer nada. Presentar argumentos de que una función respalda malos hábitos o anti-patrones o que deteriorará a la comunidad más grande de desarrolladores es igualmente una táctica atemorizante.

La mitad de las características de literalmente cualquier marco / lenguaje son peligrosas para un desarrollador; los métodos públicos pueden extenderse, Vue fomenta el acceso al elemento ($ el), etc. Los marcos proporcionan estas cosas porque al final del día el desarrollador necesita hacer el trabajo.

Esta solicitud de función tiene un año. Las personas deben entender que la razón no es en realidad porque causaría malas prácticas ni deberían percibir la reproducción retrasada como una mala práctica.

Necesito usar requirejs con vue. No es que me guste requirejs, sino porque quiero usar vue con un LMS de código abierto que tiene todos sus módulos como módulos AMD. Sería genial si pudiera cargar todas las bibliotecas que necesito en el gancho beforeCreate. La alternativa para mí en este momento es cargarlos fuera de vue y luego pasarlos en lo que es más desordenado.

Me parece que permitir el soporte asíncrono para los métodos del ciclo de vida fomentará las malas prácticas de UX de forma predeterminada. ¿Cómo? Las funciones asíncronas se utilizan para solicitudes que no se pueden completar inmediatamente (por ejemplo, solicitudes de red o de larga duración). Obligar a Vue a retrasar la creación o el montaje o cualquiera de los otros métodos del ciclo de vida para esperar su solicitud de red o un proceso asíncrono de larga ejecución afectará al usuario de manera notable. Imagine que un usuario llega a su sitio y luego tiene que esperar 4 segundos con una pantalla en blanco mientras el componente espera a que la conexión celular irregular del usuario finalice su solicitud de red. Y esto no solo tiene un impacto negativo en el usuario, sino que también está sacrificando su control sobre la situación; no hay nada que pueda hacer como desarrollador para que los usuarios perciban el tiempo de carga más rápido o muestren indicadores de progreso determinados o indeterminados. Por lo tanto, al incorporar esta capacidad en Vue, no está haciendo de la web un lugar mejor; estás habilitando malas prácticas.

Es mucho mejor planificar y diseñar para el caso asincrónico desde el principio: inicie su proceso asincrónico en created o mounted o donde sea, y luego haga que su componente tenga una estructura esquelética o en el peor de los casos una ruleta mientras espera que su API devuelva los permisos del usuario. Mucho mejor UX y no sacrificas ningún control. Y Vue no tiene que agregar código para lidiar con las funciones asincrónicas del ciclo de vida, lo que hace que el paquete sea más pequeño. Gana, gana.

Lo que está diciendo es que agregar características de v-if/v-clock/v-show fomentará las malas prácticas, por lo que es mejor que eliminemos esas características a prueba de tontos del marco. Luego use un enfoque complicado para hacer lo mismo para que Vue sea más pequeño por no poner esas 3 directivas. Los primeros desarrolladores no son estúpidos. Segundo, hacer el framework a prueba de tontos a su vez limita su usabilidad porque está limitando lo que se puede hacer basándose en aparentes "tontos". ¿Por qué uno pondría un v-if para todo su sitio web para bloquearlo a través de operaciones asíncronas dejando toda la pantalla en blanco?

Creo que está ignorando el hecho de que la mayoría de los casos de uso pueden ni siquiera tener una página en blanco. Se llaman componentes por una razón. Los casos en los que personalmente quiero usar esto es cuando algo ya está en la pantalla haciendo otra cosa. Este puede ser un componente bloqueado por un v-if por ejemplo, y activado cuando algo cambia. Sin embargo, en el proceso de renderizado por primera vez, async functions etc deben ser respetados como el componente arranca. Revisé toda la documentación de Vue en busca de esto y finalmente lo hice con una solución muy no tan bonita como los ejemplos de pirateo anteriores.

Lo que me preocupa es que alguien / incluso más tarde yo mantenga el código. Es como el infierno de devolución de llamada Promise vs Async ... Espera.

En realidad, lo veo mejorando la flexibilidad y la capacidad de control del marco de una manera fácil de seguir. Solo eche un vistazo a los trucos anteriores para ver a qué me refiero. Los desarrolladores están haciendo todo eso solo para llenar el vacío de una simple declaración async mounted () { await... } , por ejemplo. Si no desea usar esas características, simplemente no defina las funciones como async o incluso use await en absoluto.

En realidad, alguien que realmente use un gancho de ciclo async mounted vida de

@emahuni , no creo que nadie esté en desacuerdo con la expectativa que está compartiendo, pero creo que hay un matiz, que se está dejando de lado. Supongamos que async mounted o async created retrasa la renderización del componente. ¿Qué hace el padre en este caso? Lo hace:

  • bloquear también
  • suponga que el componente debe eliminarse del DOM v-if hasta que termine de cargarse
  • suponga que el componente está destinado a estar oculto hasta que se complete la carga
  • ¿Mostrar un elemento temporal en su lugar?

Si bien estoy de acuerdo en que las expectativas en torno a un componente cargado dinámicamente son consistentes, el comportamiento del padre no creo que lo sea. En estos casos, la OMI estaría exponiendo la implementación del niño al padre y obligar al padre a descubrir qué hacer con ese componente dinámico. En cambio, la forma en que se cargan los datos y el estado del componente secundario debe depender del niño. Si carga de forma asincrónica, entonces necesita alguna forma de explicarle a Vue qué se debe representar en su lugar (o no). La mejor manera de manejar eso es cómo el marco ya funciona, en lugar de introducir una nueva complejidad.

Además, no estoy siguiendo totalmente tu argumento:

Lo que está diciendo es que agregar funciones v-if / v-clock / v-show fomentará las malas prácticas, por lo que es mejor que eliminemos esas funciones a prueba de tontos del marco.

Si bien en este caso, podemos ver claramente que la introducción de componentes asincrónicos espera de la montura o creados hará que las malas prácticas, no está claro que esto hace. En segundo lugar, surge la pregunta de que, incluso si causan malas prácticas, deberíamos optar por corregirlas , en lugar de utilizarlas como justificación para crear nuevas malas prácticas. Si conoce malas prácticas que están siendo creadas por v-if , etc ... le invito a compartir explícitamente (en otro número, por supuesto) cuál es el problema con ellas, en lugar de tratar de usar eso como una justificación. para una discusión diferente.

@emahuni , no creo que nadie esté en desacuerdo con la expectativa que está compartiendo, pero creo que hay un matiz, que se está dejando de lado. Supongamos que async mounted o async created retrasa la renderización del componente. ¿Qué hace el padre en este caso? Lo hace:

  • bloquear también

El padre puede seguir adelante y rendir sin siquiera esperar al niño, ¿por qué debería hacerlo? Puede seguir adelante y ejecutar updated una vez que el niño haya renderizado.

  • suponga que el componente debe eliminarse del DOM v-if hasta que termine de cargarse

No estoy seguro de haber entendido esto ... pero la respuesta es no, no asumimos que se eliminará, solo necesita hacer algo durante el montaje que debe bloquearse durante ese tiempo. Hay muchos casos de uso leídos anteriormente para eso.

  • suponga que el componente está destinado a estar oculto hasta que se complete la carga

Esto depende del desarrollador, por qué están sincronizando el gancho montado o cualquier otro gancho.

  • ¿Mostrar un elemento temporal en su lugar?

Puede que ese no sea el caso en absoluto. Nuevamente, depende del desarrollador lo que pretendan lograr. El caso es que nada debe llevar una chaqueta recta. Cuando, por ejemplo, se diseñó v-if no fue porque concibieron por qué alguien querría bloquear la representación de un componente cada vez, y lo que colocó en su lugar y lo hizo a prueba de tontos. Hay muchas cosas que pueden salir mal con v-if por diseño del desarrollador. No debe preocuparse por lo que estará en la pantalla durante ese tiempo, no es de lo que debe preocuparse el marco.

Si bien estoy de acuerdo en que las expectativas en torno a un componente cargado dinámicamente son consistentes, el comportamiento del padre no creo que lo sea. En estos casos, la OMI estaría exponiendo la implementación del niño al padre y obligar al padre a descubrir qué hacer con ese componente dinámico. En cambio, la forma en que se cargan los datos y el estado del componente secundario debe depender del niño. Si carga de forma asincrónica, entonces necesita alguna forma de explicarle a Vue qué se debe representar en su lugar (o no). La mejor manera de manejar eso es cómo el marco ya funciona, en lugar de introducir una nueva complejidad.

Para tu información: estás de acuerdo con que esto debe implementarse, sin embargo, introducirá estas complejidades por las que estás llorando y él siente que se puede hacer más tarde cuando se introduzcan cambios importantes en lugar de en Vue 3. El punto es que él siente que es necesario .

Además, no estoy siguiendo totalmente tu argumento:

Lo que está diciendo es que agregar funciones v-if / v-clock / v-show fomentará las malas prácticas, por lo que es mejor que eliminemos esas funciones a prueba de tontos del marco.

Si bien en este caso, podemos ver claramente que la introducción de componentes asincrónicos espera de la montura o creados hará que las malas prácticas, no está claro que esto hace. En segundo lugar, surge la pregunta de que, incluso si causan malas prácticas, deberíamos optar por corregirlas , en lugar de utilizarlas como justificación para crear nuevas malas prácticas. Si conoce malas prácticas que están siendo creadas por v-if , etc ... lo invito a compartir explícitamente (en otro número, por supuesto) cuál es el problema con esas, en lugar de intentar usarlo como justificación. para una discusión diferente.

Simplemente señalé esas directivas como un ejemplo de características que se pueden usar incorrectamente para bloquear la representación de un componente similar a lo que estaba diciendo sobre async... . No tienen nada de malo. Entonces, ¿deberíamos eliminar esas directivas solo porque alguien puede usar "malas prácticas" para crear componentes que muestran páginas en blanco por un minuto? En realidad, no ves a nadie haciendo eso porque no sucede, a menos que estés tratando de dar un ejemplo de la mayor maldad como algo horrible.

Mire, el punto es que, si aún no puede ver ningún caso de uso, entonces no diga que otras personas lo usarán mal y, por lo tanto, no debería hacerse. La mala práctica es una cuestión de ignorancia y es posible que alguien tan ignorante nunca use estas funciones por completo.

Alguien preguntó esto https://github.com/vuejs/vue/issues/7209#issuecomment -424349370 allí y nadie le respondió por lo que vi. Esto es, con mucho, una muestra genuina de que Vue se está quedando atrás en esta parte. Esta parte de la arquitectura se diseñó cuando la async aún no existía. Por lo tanto, actualizarlo para cumplir con los requisitos modernos de las arquitecturas modernas es una buena idea. De lo contrario, el resto son trucos y soluciones que necesitan formas específicas de hacerlo en lugar de hacer lo que está sucediendo en la industria.

Sin embargo, todavía no estoy seguro, pero al mirar la nueva API funcional de un vistazo, parece que en realidad puede ser posible hacer esto. Dado que es funcional, significa que uno puede hacer ciertas cosas que no podría hacer objetivamente, como los ganchos de ciclo de vida asíncronos.

Mire, el punto es que, si aún no puede ver ningún caso de uso, entonces no diga que otras personas lo usarán mal y, por lo tanto, no debería hacerse. La mala práctica es una cuestión de ignorancia y es posible que alguien tan ignorante nunca use estas funciones por completo.

Nunca hice ese punto, estoy señalando que quiero realizar acciones asíncronas de forma predeterminada sin bloquear la representación del componente. No es intuitivo que la realización de acciones async en un bloque mounted o created provoque un retraso en la representación del componente. Suponiendo que este fuera el caso, vería que la complejidad surge de cómo procedería un consumidor que desea la funcionalidad actual. El argumento hasta ahora no es que lo que se pide no se puede hacer, es que lo que se pide debe ser el predeterminado. Ya puede bloquear la representación de su componente cambiando la plantilla mostrada según un v-if="loaded" .

Ahora mismo, para renderizar sin bloquear el código se ve así:
Ahora mismo ese código es:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
    this.loaded = true;
  }
</script>

Y renderizar con bloqueo se ve exactamente de la misma manera, ya que en realidad no se puede bloquear. Suponiendo que async created() bloqueó realmente el componente. Entonces ahora tenemos una separación de código. Para mostrar la ruleta, escribimos:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  created() { 
    this.loadData().then(() => this.loaded = true);
  }
</script>

y simplemente ignore la representación del componente en la pantalla que escribimos

<template>
  <div>  
    <div>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
  }
</script>

¿Para qué beneficia agregar esta simplificación para bloquear la representación, lo que hace que no bloquear sea más complicado? Simplemente no lo estoy viendo.

Manejo de dependencias para componentes

@ yyx990803 Por favor, mire esto, no es perfecto, pero es un escenario de caso de uso complejo.

Ok, aquí hay un caso de uso que podría haberse manejado con elegancia si los ganchos del ciclo de vida hubieran sido asíncronos ... aguardar:
_De hecho, deseaba hacer esto en una aplicación y obtuve un código feo para lograrlo. Este es un ejemplo muy elaborado de coz_

Necesito que el componente A espere a que se activen los ganchos mounted componente B && C antes de montarse. Por lo tanto, el mounted componente A tiene que esperar su gancho created , que desencadenó el montaje del componente B && C que estaba esperando el disparador _ (que en realidad puede hacer algo antes de esperar) _. La cosa es que es más fácil de esta manera y mucho más limpio e intuitivo, ya que todo permanece en un solo lugar para el componente en cuestión.

A emite un evento de disparo y la escucha de las respuestas de B y C _ (B y C de espera para la señal A 's antes de continuar, eventos entonces emitir montados una vez) _ antes de continuar, simple. Esto es más como un escenario de dependencia para componentes sin datos extraños esparcidos en otros lugares para la gestión estatal.

Componente de alojamiento principal , todos los componentes se cargan juntos, pero espere los correctos usando eventos y async ... aguarde. No importa lo que hagan estos niños, se ordenan a sí mismos.

<template>
  <div>
     ...
     <component-A/>
     <component-B/>
     <component-C/>
     ... other conent
  </div>
</template>
<script>
  import ComponentA...
  ...
  export default {
      components: { ComponentA... }
  }
</script>

El componente A controla el montaje de B y C como dependencias. La activación podría realizarse más tarde en otros ganchos o incluso a través de un evento UX de los mismos componentes. Lo siguiente es solo para mostrar la idea aquí.

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here before mounting thrusters, even await it
         this.root.$emit('mount-thrusters');
         await Promise.all([
            this.wasMounted('thruster-1-mounted'), 
            this.wasMounted('thruster-2-mounted')
         ]); 
      },
      mounted() {
        // will only run after components B and C have mounted
        ...
      },

     methods: {
       wasMounted(compEvent) {
          return new Promise( (resolve)=>this.root.$once(compEvent, ()=>resolve()));
       }
    }
  }
</script>

componente B

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here, even await it, but happens at the same time as all components
         await new Promise( (resolve)=>this.root.$once('mount-thrusters', ()=>resolve()));
      },
     mounted() {
       this.root.$emit('thruster-1-mounted');
    }
  }
</script>

componente C

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here, even await it, but happens at the same time as all components
         await new Promise( (resolve)=>this.root.$once('mount-thrusters', ()=>resolve()));
      },
     mounted() {
       this.root.$emit('thruster-2-mounted');
    }
  }
</script>

El código anterior se puede simplificar aún más mediante mixins, ya que hay muchos fragmentos de código duplicados, solo quería que fuera claro. El método wasMounted puede enlatarse en una mezcla y usarse en los 3 componentes.

Aquí podemos ver claramente lo que espera cada componente sin ningún otro código de enrutador o pirateo en otro lugar para controlar lo mismo. Es muy confuso hacer esto sin esta función, créanme, lo hice en una aplicación.

Obviamente, esto elimina el código innecesariamente complejo y que no se puede mantener.

Ahora imagine esto en una aplicación grande, con 32 componentes de propulsión que se comportan de manera diferente. Solo tendrás unos 3 puntos en mente, que se pueden reducir incluso a 2 si agregas mixins.

Hacer que las cosas se mantengan frescas

Por supuesto, esto no solo se limita a montar y crear, sino que en realidad debería funcionar con todos los demás ganchos del ciclo de vida. Imagínese si esto está en un nuevo y brillante gancho beforeActivate / beforeUpdate . Podríamos hacer que el componente espere _activación / actualización_ y solo _activar / actualizar_ cuando se realiza el refresco cada vez que el componente se _activa / actualiza_; asegurándose de que las cosas se mantengan frescas.

La lista es interminable una vez que esto se implementa.

Mire, el punto es que, si aún no puede ver ningún caso de uso, entonces no diga que otras personas lo usarán mal y, por lo tanto, no debería hacerse. La mala práctica es una cuestión de ignorancia y es posible que alguien tan ignorante nunca use estas funciones por completo.

Nunca hice ese punto, estoy señalando que quiero realizar acciones asíncronas de forma predeterminada sin bloquear la representación del componente. No es intuitivo que la realización de acciones async en un bloque mounted o created provoque un retraso en la representación del componente. Suponiendo que este fuera el caso, vería que la complejidad surge de cómo procedería un consumidor que desea la funcionalidad actual. El argumento hasta ahora no es que lo que se pide no se puede hacer, es que lo que se pide debe ser el predeterminado. Ya puede bloquear la representación de su componente cambiando la plantilla mostrada según un v-if="loaded" .

Ahora mismo, para renderizar sin bloquear el código se ve así:
Ahora mismo ese código es:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
    this.loaded = true;
  }
</script>

Y renderizar con bloqueo se ve exactamente de la misma manera, ya que en realidad no se puede bloquear. Suponiendo que async created() bloqueó realmente el componente. Entonces ahora tenemos una separación de código. Para mostrar la ruleta, escribimos:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  created() { 
    this.loadData().then(() => this.loaded = true);
  }
</script>

y simplemente ignore la representación del componente en la pantalla que escribimos

<template>
  <div>  
    <div>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
  }
</script>

¿Para qué beneficia agregar esta simplificación para bloquear la representación, lo que hace que no bloquear sea más complicado? Simplemente no lo estoy viendo.

Este es el campamento de entrenamiento Vue 101 y no hay nada nuevo allí ... no es suficiente para cubrir los casos anteriores, por ejemplo. La idea aquí es reducir la complejidad en el área de usuario donde realmente se usa Vue y aprovechar el código más fácil de razonar.

El renderizado aquí no es el problema, es lo que está sucediendo antes del renderizado lo que realmente tiene importancia. Queremos la libertad de hacer cosas antes de proceder o renderizar un componente. De todos modos, esto tampoco tiene nada que ver con bloquear el renderizado. Hay muchos ganchos de ciclo de vida que admite Vue y estos pueden ser útiles si hubiera una forma de manejar el código asíncrono contra otros ganchos. La idea es que Vue respete async internamente antes de pasar a la siguiente función de enlace.

Estoy realmente confundido por esto, en lugar de acoplar B y C a A, movería el código para "cargar A" en A.js y luego hacer que A.js actualice "B.data" y "C.data" . De esa forma, si los datos A. cambian por cualquier motivo, los otros componentes se vuelven a generar automáticamente en lugar de intentar delegar
control de un componente a otro. Incluso en el caso compartido, todavía desacoplaría los datos para representar A del componente A. Hemos utilizado una sola clase que contiene métodos como fetchData y hasInitialized para el cual el último es una promesa y el primero resuelve el segundo.
El acoplamiento directo de los componentes entre sí crea árboles de dependencia inesperados que evitan que los componentes sean reutilizables y permiten que vue los vuelva a procesar correctamente.

Alternativamente, incluso emit el evento directamente al padre de A, B y C, y no en el alcance global, y dejaría que el padre decida si renderizar B y C, es decir

  <template>
    <a-component @rendered="showBandC = true" />
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>

¿Qué tiene A que en este caso realmente necesitaríamos renderizar antes de que B y C se rendericen? Si hay cosas en el método created() , nada impide que llene la tienda a través de una clase javascript o usando un módulo store . Pero el caso de uso explícito sería más útil, es decir, ¿cuál es la UX de la historia del usuario que no se puede capturar?

La idea es que Vue respete async internamente antes de pasar a la siguiente función de enlace.

Seguro que esa parte tiene sentido, pero no estoy seguro de por qué el ejemplo debe ser complicado, por qué no decir algo como esta historia de usuario:

Mi componente tiene async beforeMount y async mounted , pero el código en mounted se activa antes de que se complete el código en beforeMount . ¿Cómo podemos bloquear mounted disparen antes beforeMount se ha completado?

Que es algo así como la solicitud original, por lo que la pregunta que se planteó en la segunda respuesta creo que sigue siendo relevante: https://github.com/vuejs/vue/issues/7209#issuecomment -350284784

Cerrando por ahora, pero siéntase libre de hacer un seguimiento con razonamientos / casos de uso / implicaciones más concretos.

¿Existe realmente un caso de uso válido para la necesidad de bloquear en los ganchos del ciclo de vida ejecutados anteriormente, o es correcto que los ganchos del ciclo de vida sean síncronos? Hasta ahora, la discusión ha sido de naturaleza filosófica (como tienden a ser las buenas discusiones sobre arquitectura), pero realmente la pregunta es si ha habido una buena razón real para hacer esto. No dudo ni por un segundo que es razonable que el marco espere el código asíncrono. Tuve el problema exacto en otras N bibliotecas que no hicieron eso o pasaron una devolución de llamada (o pasaron una devolución de llamada pero no pasaron una devolución de llamada a la devolución de llamada). Sin embargo, ¿es realmente razonable tener un enlace de ciclo de vida asíncrono o son las razones el resultado de intentar hacer algo que "no debería hacerse"?

Es decir, lo que sucede cuando intentas unmount un componente que no ha terminado de ser created , vaya, sería malo estar esperando eso todavía. O destroying uno que no ha terminado de ser mounted , no envidio al implementador de esa funcionalidad.

Estoy realmente confundido por esto, en lugar de acoplar B y C a A, movería el código para "cargar A" en A.js y luego hacer que A.js actualice "B.data" y "C.data" . De esa forma, si los datos A. cambian por cualquier motivo, los otros componentes se vuelven a generar automáticamente en lugar de intentar delegar

Eso es complejidad aumentada, mala práctica. Intente escribirlo aquí en su totalidad, veamos qué quiere decir, pero para mí, acaba de aumentar mucho la complejidad.

control de un componente a otro. Incluso en el caso compartido, todavía desacoplaría los datos para representar A del componente A. Hemos utilizado una sola clase que contiene métodos como fetchData y hasInitialized para el cual el último es una promesa y el primero resuelve el segundo.

Esto ahora está acoplando demasiado los componentes. Queremos que estos funcionen sin el otro a excepción de A.

El acoplamiento directo de los componentes entre sí crea árboles de dependencia inesperados que evitan que los componentes sean reutilizables y permiten que vue los vuelva a procesar correctamente.

De hecho, se está perdiendo el punto, estos están vagamente acoplados hasta el punto de que cada uno se puede usar y mantener sin afectar al otro. De hecho, puede colocar cualquiera de ellos varias veces en cualquier lugar sin escribir más código en los padres fuera de <component-x /> , no v-if , vuex para administrar su estado ni nada más.

Los acoplé A a B y C solo para demostrar, podría haber dividido esto muy bien o simplemente contar cuántos componentes han respondido y luego continuar cuando se alcanza un cierto número esperado (2 en este caso), por ejemplo:

 this.$root.$emit('thruster-mounted') // in B and C
// instead of 
 this.$root.$emit('thruster-1-mounted') // for B and 2 for C

// then count the responses and resolve once they are >= 2 in component A

De todos modos, es por eso que dije Manejo de dependencias de componentes, esto es deseado y esperado, pero debe hacerse con la menor complejidad posible porque cuanto más complejo se vuelve, más confuso se vuelve.

Alternativamente, incluso emit el evento directamente al padre de A, B y C, y no en el alcance global, y dejaría que el padre decida si renderizar B y C, es decir

Sabía que ibas a decir esto, pero no es deseado. Estos componentes no deben ser controlados por nada más, por lo tanto, enfaticé que al componente principal le importa menos lo que hagan sus hijos, deben permanecer independientes. Quiero poder colocarlos en cualquier lugar de la aplicación y aún así hacer que esto mismo funcione . En el momento en que hagas lo que dices, observa cómo todo se rompe. Pero puedo colocar fácilmente componentes en cualquier lugar del árbol DOM sin siquiera estremecerme, y todo funcionará. Incluso puedo tener varias copias de esto y seguirá funcionando. Todo gracias a async ... await en los ciclos de vida.

  <template>
    <a-component @rendered="showBandC = true" />
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>

¿Qué tiene A que en este caso realmente necesitaríamos renderizar antes de que B y C se rendericen?

Queremos que cada componente realice un trabajo único antes de montarlo. Pero todos los componentes solo se renderizarán cuando todos los demás componentes hayan terminado de hacer ese trabajo. Esa es la historia aquí.
Así que buena suerte con la administración estatal y v-if solo para controlar esto sin mencionar los datos reales que probablemente producirá en la tienda vuex . Terminará teniendo mucho código duplicado escrito donde sea que se use el componente. Digamos que tiene otro componente que aloja A y C solamente y en una configuración diferente. Tienes que escribir esos v-if , la administración del estado de vuex para que eso funcione. ¿Ves el problema? déjame ilustrar:

  // component Z totally different from foo, so we can't make this a component for reuse
  <template>
    <a-component @rendered="showBandC = true" />
    <c-component v-if="showBandC" />
  </template>
 ...
computed: {
showBandB() { ...vuex ...,
showBandC() { ...vuex ...,
}
  // component Foo totally unique, probably has other things it does
  <template>
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>
 ...
computed: {
// ok you could mixin this, fair, but complex nevertheless
showBandB() { ...vuex ...,
showBandC() { ...vuex ...,
}

..... y así sucesivamente

en lugar de simplemente usar los componentes sin hacer nada en los padres así:

  // component Z
  <template>
    <a-component />
    <b-component />
  </template>
  // component Foo
  <template>
    <b-component  />
    <c-component />
  </template>

... Etcétera

Si hay cosas en el método created() , nada impide que llene la tienda a través de una clase javascript o usando un módulo store . Pero el caso de uso explícito sería más útil, es decir, ¿cuál es la UX de la historia del usuario que no se puede capturar?

¿Recuerda lo que dije sobre la gestión estatal esparcida por todas partes? No queremos que porque la gestión de estos componentes signifique que gestionaremos muchas cosas en otros lugares, lo cual es muy complejo en lugar de lo que acabo de hacer. Además, no hará lo que quiero que haga; solo monte cuando cada componente haya completado lo que se supone que debe hacer con muy poca complejidad.

La idea es que Vue respete async internamente antes de pasar a la siguiente función de enlace.

Seguro que esa parte tiene sentido, pero no estoy seguro de por qué el ejemplo debe ser complicado, por qué no decir algo como esta historia de usuario:

Mi componente tiene async beforeMount y async mounted , pero el código en mounted se activa antes de que se complete el código en beforeMount . ¿Cómo podemos bloquear mounted disparen antes beforeMount se ha completado?

El punto es que queremos que sucedan cosas antes de que cualquiera de estos componentes se procese y sea utilizable sin demasiada entrada fuera de los propios componentes. Esto es algo real que noté que podría haberlo hecho mejor si estuviera disponible una aplicación que estamos haciendo. Terminé escribiendo un código que tiene muchos mixins, vuex y padres fuertemente acoplados en todas partes (usando mixins) los componentes se usaron porque falta esto. Esta no es una historia complicada, en realidad les estoy contando lo que sucedió de una manera simple. Tuvimos que repensar cómo se suponía que debía diseñarse y mantenerse la interfaz de usuario. Se volvió un poco menos interesante visualmente y mucho más complejo en cuanto al código.

¿Ves cuántas cosas complejas introdujiste en esta configuración simple que acaba de ser resuelta por esa pequeña función async ... await en los ciclos de vida?

@wparad

Es decir, lo que sucede cuando intentas desmontar un componente que no ha terminado de crearse, vaya, sería malo estar esperando eso todavía. O destruir uno que no ha terminado de montarse, no envidio al implementador de esa funcionalidad.

Aquí es donde:

... requiere un replanteamiento / reescritura fundamental de la arquitectura para lograrlo, y potencialmente puede romper mucha lógica que se basa en la naturaleza sincrónica de los ganchos del ciclo de vida ...

... parte que creo que fue mencionada por ti. Necesitamos una forma de manejar estos casos extremos y probablemente más de lo que esto introduce. En otras palabras, nuestras intenciones deben funcionar sin bloquear la aplicación.

En todos esos casos, usaría tiempos de espera para verificar o cancelar la espera, al igual que la mayoría de las operaciones asíncronas que pueden fallar.

Pero si observa detenidamente el ejemplo que presenté, verá a qué me refiero. Esto podría haber resuelto muchas cosas, sin mucho código escrito en ninguna parte. De hecho, nuestra aplicación podría haber sido mucho mejor con una base de código mucho más pequeña, desfragmentada y fácil de entender si esto fuera posible.
Lo que pasa con este tipo de funciones es que solo ves su importancia una vez que te encuentras con un obstáculo. Llegué a esta página por primera vez cuando habíamos pensado en muchas soluciones para este mismo ejemplo que acabo de dar. No había venido a buscar ayuda, era para presentar una solicitud de función ya que notamos que no estaba disponible en Vue.

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

Temas relacionados

guan6 picture guan6  ·  3Comentarios

franciscolourenco picture franciscolourenco  ·  3Comentarios

paulpflug picture paulpflug  ·  3Comentarios

seemsindie picture seemsindie  ·  3Comentarios

hiendv picture hiendv  ·  3Comentarios