Vue: Aguarde ganchos de ciclo de vida do componente assíncrono

Criado em 8 dez. 2017  ·  51Comentários  ·  Fonte: vuejs/vue

Qual problema esse recurso resolve?

Se um usuário precisa implementar um gancho de ciclo de vida que depende de operações assíncronas, o vue deve respeitar a natureza assíncrona do gancho implementado e aguardá-lo em tempo real.

Qual é a aparência da API proposta?

A API não muda; apenas como funciona agora, aguardando ganchos assíncronos.

Comentários muito úteis

Este é o código real que desejo esperar:

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

Que faria parte do componente UserPage .

Todos 51 comentários

Então você quer

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

mostrar

mounted

?

Ao criar uma solicitação de recurso, adicione um caso de uso do mundo real para fazer com que a solicitação valha a pena ser implementada.

Embora seja teoricamente uma ideia legal, isso requer um repensar / reescrever fundamentalmente a arquitetura para ser alcançado, e pode quebrar muitas lógicas que dependem da natureza síncrona dos ganchos do ciclo de vida. Portanto, os benefícios devem ser substanciais para justificar essa mudança - caso contrário, isso só pode ser considerado quando planejamos fazer uma atualização completa, o que é improvável que aconteça muito em breve.

Encerrando por enquanto, mas fique à vontade para continuar com raciocínios / casos de uso / implicações mais concretos.

@posva Entendido - peço desculpas. Meu caso de uso real é aquele em que tenho um componente UserPage que recebe user_id dos parâmetros de rota da página (por meio de this.$route.params ) e, em seguida, busca os dados reais do usuário no banco de dados no servidor usando um comando como:
this.user = await client.get({type: 'user', id: this.$route.params.id})
onde this.user se refere a um campo user na parte data do componente UserPage .

Idealmente, eu quero que essa linha de código seja executada após o componente ter sido criado (para que this.$route.params esteja disponível), mas antes que o componente seja realmente montado para que em meu modelo eu possa usar user com segurança

@ yyx990803
Posso ser um novato aqui, mas a única mudança não deveria ser adicionar a palavra-chave await antes da chamada para ganchos de ciclo de vida como mounted , etc, na terra Vue?

Este é o código real que desejo esperar:

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

Que faria parte do componente UserPage .

Sem problemas! Eu estava imaginando esse caso de uso. É melhor lidar com isso conforme descrito nos documentos do vue-router, pois ele abre diferentes maneiras de exibir o estado de carregamento. Você já pode esperar que os dados estejam lá antes de renderizar o componente btw.

OK, isso faz sentido. Agora, no entanto, e se eu tiver um componente de usuário que é uma versão simplificada da página do usuário (digamos, como o componente que aparece quando você passa o mouse sobre o nome de um usuário no Facebook e "espia" em seu perfil), o roteador não está envolvido aqui e id será passado como uma propriedade para o componente.

Tendo a visão geral aqui, as funções em JavaScript agora podem ser síncronas ou assíncronas, e os ganchos de ciclo de vida sendo funções, e a maneira como pensamos neles como funções, devem oferecer suporte à assincronização (conforme demonstrado pelo meu caso de uso e "alcance" intuitivo para a abordagem que estou usando aqui).

Você tem muitas maneiras de fazer isso. O mais simples é usar uma variável que começa como nula, buscar os dados e configurá-los, alternando o componente real (por causa de um v-if). Uma versão mais exótica seria uma função que resolve o componente e usa um <component :is="myDynamicComp"/> 😄
Mas, por favor, não transforme o problema em uma pergunta 😉 use o fórum ou discórdia para isso

Não, realmente não quero ajuda com o código! Na verdade, implementei soluções alternativas muito semelhantes às suas sugestões. O que estou tentando dizer é que é muito mais intuitivo apenas usar os recursos assíncronos JS.

A parte que não percebi é que o código assíncrono e o síncrono são fundamentalmente diferentes por natureza, de modo que o código síncrono não pode ser forçado a aderir ao código assíncrono sem mudar fundamentalmente para o código assíncrono. yyx990803 vi imediatamente, mas demorei algum tempo para entender seu comentário completamente. Obrigado pelo seu tempo pessoal e desculpe se houve um erro de comunicação da minha parte em algum lugar do caminho.

Eu tenho alguns casos de uso aqui e gostaria de obter alguma sugestão e método de solução alternativa.

MainPage.vue é meu contêiner principal. Eu chamo ajax de "/ init" em beforeCreate para obter informações do usuário e, em seguida, comprometo-me com Vuex.store.
Content.vue é a criança dentro de MainPage.vue . Eu gostaria de chamar diferentes chamadas de api no estágio mounted acordo com a função do usuário que vem de Vuex.store.

Se o ciclo de vida chamar em fluxo assíncrono / aguardar, ele seguirá a ordem
Parent beforeCreate -> Parent create -> Child beforeCreate -> Child create -> Child montado .... (Se eu entendi corretamente sobre o ciclo de vida do componente).

Mas atualmente não consigo obter informações do usuário em Content.vue , como posso obter uma solução alternativa agora?
Eu gostaria de manter a api "/ init" chamada dentro de MainPage.vue porque ela é usada em muitas páginas (container no Vue-Router).

postou pergunta sobre stackoverflow

Obrigado

uma solução alternativa para o que vale a pena:

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


Uma possível solução mais "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
        }
    }
}

Isso ainda não é uma coisa?

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

Está trabalhando para mim (como @fifman menciona).

@breadadams Sim, claro. As funções _inside_ o método created serão aguardadas - entretanto a função created ou mounted si não é.

Assim, a instância Vue chamará created e instantaneamente mounted antes que qualquer um dos processos de longa execução em created seja concluído

Ah , meu mau @ darren-dev - caso de uso diferente do meu lado, mas vejo o problema agora 😅 obrigado por esclarecer.

@breadadams Sem problemas - estamos todos aqui para

O gancho de ciclo de vida assíncrono pode ser uma boa implementação na próxima versão principal

Parece-me que permitir o suporte assíncrono para os métodos de ciclo de vida irá encorajar práticas ruins de UX por padrão. Como? As funções assíncronas são usadas para solicitações que não podem ser concluídas imediatamente (por exemplo, solicitações de longa duração ou de rede). Forçar o Vue a atrasar a criação ou montagem ou qualquer um dos outros métodos de ciclo de vida para aguardar sua solicitação de rede ou processo assíncrono de longa duração afetará o usuário de maneiras perceptíveis. Imagine um usuário acessando seu site e tendo que esperar 4 segundos com uma tela em branco enquanto o componente espera que a conexão de célula irregular do usuário conclua sua solicitação de rede. E isso não apenas afeta negativamente o usuário, mas também está sacrificando seu controle sobre a situação - não há nada que você possa fazer como desenvolvedor para tornar o tempo de carregamento percebido pelos usuários mais rápido ou mostrar indicadores de progresso determinados ou indeterminados. Portanto, ao construir essa capacidade no Vue, você não está tornando a web um lugar melhor; você está habilitando práticas inadequadas.

É muito melhor planejar e projetar para o caso assíncrono desde o início: inicie seu processo assíncrono em created ou mounted ou qualquer outro lugar e, em seguida, faça com que seu componente tenha uma estrutura de esqueleto ou, na pior das hipóteses um botão giratório enquanto você espera que sua API retorne as permissões do usuário. UX muito melhor e você não sacrifica nenhum controle. E o Vue não precisa adicionar código para lidar com funções de ciclo de vida assíncronas, mantendo o pacote menor. Vitória, vitória.

@seanfisher Você levantou um ponto válido. Do ponto de vista arquitetônico, o projeto em torno de um conjunto assíncrono de eventos deve ser tratado pelo desenvolvedor - já que é a única maneira de retratar a mensagem corretamente.

Isenção de responsabilidade : o texto a seguir foi escrito com a ideia de geração de página em mente. Definitivamente, existem casos de uso válidos em que meu argumento é inválido.


No entanto, ditar os padrões de design de um desenvolvedor não deve ser deixado para a estrutura que você está usando. Meu argumento é que, se você não está esperando a conclusão de uma fase, por que ter fases diferentes? Por que criar um palco e depois montar? Se tudo está basicamente acontecendo de uma vez, então ignorar completamente o estágio criado está certo.

Literalmente, a única vez que (desde o início do Vue) me enganchei na criação foi quando tive que injetar algo em que vue precisava confiar - não tinha nada a ver com a configuração ou o layout da minha página. No entanto, tive que esperar a execução de tarefas assíncronas (curtas) que seriam muito melhores _antes_ da página ser renderizada (como a conexão com os métodos de autenticação do Firebase). Ter isso na criação e, em seguida, esperar que ele seja concluído antes de montá-lo reduziria a necessidade de soluções alternativas.

Lembre-se, meu argumento é que Vue não deveria me dizer que estou desenvolvendo errado. Ele deve apenas fornecer a funcionalidade desejada.

No entanto, ditar os padrões de design de um desenvolvedor não deve ser deixado para a estrutura que você está usando.

Hum .... Frameworks são construídos especificamente para limitar, guiar ou "enquadrar" o desenvolvedor em certos padrões e práticas de design. Esse é o seu objetivo principal. Qualquer bom framework oferecerá uma API inteligente, que oferece precisamente uma maneira clara e óbvia de trabalhar com o framework e ainda assim será restritiva.

Sim, é paradoxal que um framework ofereça certas habilidades, mas também restrinja o desenvolvedor ao mesmo tempo a certas práticas de design. É exatamente aí que a opinião dentro das Estruturas pode ajudar ou prejudicar. É difícil encontrar o equilíbrio certo e acho que a Vue, ou melhor, Evan e a equipe de desenvolvimento da Vue fizeram e estão fazendo um ótimo trabalho ao fazer esses julgamentos.

Scott

Nunca vou argumentar que uma estrutura bem projetada deve ser estendida com o mesmo padrão de design, mas meu argumento é que a estrutura não pode ditar isso. Você está correto, mas estou dizendo que não importa o quão bom seja o framework, o desenvolvedor final ainda deve estar aberto para fazer o que quiser.

Mas você não tocou no argumento _real_ de tornar os eventos criados e montados assíncronos - você apenas adicionou sua opinião (o que não está errado) na minha opinião, o que geralmente leva a um grande descarrilamento.

Nunca vou argumentar que uma estrutura bem projetada deve ser estendida com o mesmo padrão de design, mas meu argumento é que a estrutura não pode ditar isso.

Desculpe, mas isso não faz sentido para mim. Por favor, mostre-me uma estrutura que não dita como deve ser estendida.

Achei que dizer "Evan e companhia fazendo ligações com bom senso" mostraria minha opinião. Mas, para ser mais claro. Os ganchos de ciclo de vida montados e criados não precisam funcionar de forma assíncrona, ou melhor, o fato de trabalharem de forma síncrona ajuda a raciocinar sobre a lógica do aplicativo. Qualquer "espera" precisa ser contabilizado na IU de qualquer maneira e o código assíncrono ainda pode ser executado em cada gancho. Podemos argumentar sobre agora necessários os ganchos beforeMount e mount. Mas, pode haver uma ou duas coisas que você pode precisar em montado, por exemplo, que você ainda não pode acessar em criado, como a função de renderização compilada.

Scott

Se Vue tem uma opinião de uma forma ou de outra sobre ganchos de ciclo de vida assíncronos, não deve ser uma questão de especulação. Não há necessidade de especular quando os padrões, APIs, guias e práticas recomendadas que a Vue adota, fornece ou recomenda estão disponíveis para todos lerem.

Na resposta original de Evan, os ganchos de ciclo de vida assíncronos não estão na API padrão, não porque seja necessariamente uma má ideia, mas porque os benefícios não são substanciais o suficiente para justificar o custo de implementação.

Para a opinião de que é uma má prática fazer o usuário esperar por um gancho assíncrono created ou outro gancho de ciclo de vida sem um indicador de que algo está acontecendo, pode-se argumentar que o Vue, tendo suportado ganchos assíncronos, agora talvez fornece algo que poderia ser chamado de "modelos de fase" que também resolveria o problema (e que poderia ser fácil de implementar).

Para a opinião de que é uma má prática fazer o usuário esperar por uma criação assíncrona ou outro gancho de ciclo de vida sem um indicador de que algo está acontecendo,

Isso é mesmo um problema?

Scott

Este é o problema que estou tendo - e talvez alguém possa sugerir como DEVO fazer isso porque parece problemático.

Nosso aplicativo Vue (bastante grande) usa Vuex extensivamente. Em alguns de nossos componentes Vue no ciclo de vida create (), definimos via store.dispatch () alguns itens na loja (obviamente). No entanto, como chegou ao meu conhecimento - store.dispatch () SEMPRE retorna uma promessa .. mesmo se a lógica e a função subjacentes NÃO forem assíncronas. Então eu coloquei async created () {await store.dispatch ('foo / action')}, mas como observado, isso realmente falha.

Eu também estou usando o Typescript e ele reclama amargamente quando eu não espero /. Então as chamadas store.dispatch () .. tendo promessas "flutuantes" ..

Então, qual é a melhor maneira de usar Vuex store.dispatch () em um ciclo de vida quando não podemos assíncronizá-los?

Saúde!!

Todas as outras discussões sobre as opiniões específicas da vue, e se as estruturas devem impor opiniões à parte, pode ser benéfico documentar esse comportamento de forma mais clara.

Estou olhando para a solução "mais simples" de mounted() retornar. Nessa solução, tanto created() quanto mounted() são assíncronos, então Vue chamará cada um deles e eles retornarão mais ou menos imediatamente, com o material assíncrono acontecendo em segundo plano. Na verdade, não tenho certeza de como isso é melhor do que simplesmente acabar com createdPromise e apenas fazer todo o trabalho assíncrono em created() ou mounted() , como:

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

Em qualquer caso, my_data_member será preenchido "mais tarde" quando o XHR for concluído, muito depois de mounted() retornar sua promessa, certo?

Você também pode tentar usar v-if no componente raiz <div id="app"/> e acioná-lo quando o carregamento de dados terminar. Eu, por exemplo, uso-o para token de atualização.

Esse é um recurso legal de se ter e muitos casos de uso. Para o meu caso de uso, preciso carregar propriedades específicas da API antes da renderização real do componente. No entanto, não acho que assíncrono em ganchos de ciclo de vida seja uma solução ideal.

Atualmente, todos estão mencionando aqui um cenário perfeito onde as funções assíncronas funcionam sem problemas. Mas digamos, por exemplo, se a conexão do usuário for lenta ou atrasada e esperarmos que o componente seja montado após a resposta de uma API, todo o ciclo de vida do componente é distribuído. Não poderemos mostrar informações de carregamento ao usuário. Ou, muito pior, se a API atingir o tempo limite ou retornar um erro, o aplicativo irá travar sem montar.

Embora esse seja um recurso interessante, eu sugeriria que ele fosse tratado pelo aplicativo em vez da estrutura, porque a implementação da lógica de domínio tem mais insight sobre a lógica subjacente do que a estrutura, criando menos efeitos colaterais.

1 para este recurso.
Eu tenho um mixin usado por vários componentes, o mixin busca dados de um banco de dados no gancho montado.
Os componentes têm que trabalhar com os dados buscados pelo mixin também no gancho montado.
Como está agora, eu tive que implementar um retorno de chamada a ser chamado quando o mixin terminar de carregar os dados e liberar o gancho montado no componente.
Funciona, mas seria mais bonito se o gancho montado atendesse às promessas.

@cederron puramente por interesse, por que você não pode baixar os dados no componente pai e passá-los como um suporte? use um v-if para mostrar um indicador de carregamento enquanto os dados são carregados e quando os dados aparecem, você pode mostrar o componente e, quando for criado, terá todos os dados de que precisa.

Evita que o componente represente dois estados distintos não relacionados ('nenhum dado carregado, esperando' e 'os dados foram carregados, você pode manipulá-los')

Se você precisar reutilizar a lógica em vários lugares, pode até mesmo mover a lógica de download para o Vuex, meio que faz sentido, pois o download de dados iria em uma ação Vuex em vez de um componente.

@ReinisV Acho que simplifiquei muito meu caso, o componente cria novos dados a partir dos dados buscados pelo gancho montado no mixin e a visualização do componente é vinculada a esses novos dados.
Então, o mixin tem que buscar dados do banco de dados> o componente cria dados a partir dele> agora o componente é mostrado

AFAIK isso não vai 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 no gancho de montagem do componente.

Atualmente eu executo um retorno de chamada quando o mixin busca os dados, mas seria mais bonito apenas tornar a função de montagem assíncrona.

Não posso falar muito sobre o vuex, pois não o estou usando

Eu realmente quero reiterar o que @seanfisher mencionou aqui. Ter vue wait em componentes que foram marcados como assíncronos não só causa problemas para os usuários, mas o padrão de usar async / await para iniciar a consulta de dados está presente em todos os lugares. Isso forçaria a conversão explícita do código nesses ganchos de ciclo de vida em promessas inéditas para evitar explicitamente o bloqueio de vue. Em alguns casos, pode ser bom, e se um recurso for introduzido, eu teria que sugerir a execução de dois ciclos de vida ao mesmo tempo, o atual que lida com a execução de ganchos de componentes e outro que aguarda essas execuções para retornos de chamada globais.

Mas eu realmente ficaria desapontado se literalmente reescrevesse cada um dos meus ganchos de ciclo de vida para evitar o bloqueio de vue, async/await é muito mais limpo, então não usamos promessas. Mudar isso de uma maneira não compatível com versões anteriores muda o poço de sucesso (ciclo de vida do componente não esperado) para um poço de falha.

É muito melhor planejar e projetar para o caso assíncrono desde o início: inicie seu processo assíncrono em created ou mounted ou qualquer outro lugar e, em seguida, faça com que seu componente tenha uma estrutura de esqueleto ou, na pior das hipóteses um botão giratório enquanto você espera que sua API retorne as permissões do usuário. UX muito melhor e você não sacrifica nenhum controle. E o Vue não precisa adicionar código para lidar com funções de ciclo de vida assíncronas, mantendo o pacote menor. Vitória, vitória.

@seanfisher Obrigado, isso é super útil!

Por que não usar um componente assíncrono, que será renderizado apenas quando as chamadas assíncronas forem retornadas?
mais informações sobre a API aqui
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')
})

embora a maioria dessas soluções pareça boa, acho que essa é uma das principais peças do Vue que faltam e que o tornam tão intuitivo. Acho que o Vue 3 precisa implementar isso, pois chegamos ao ponto em que usar async await agora é uma coisa diária. SO PLEASE @ yyx990803 Você, vamos fazer isso no Vue 3. PLEEEEEEEASE. Toda a arquitetura VUE foi feita sem suposições para esses casos e a maioria das coisas que as pessoas estão postando aqui são apenas soluções alternativas e hackeadas. Acho que os ganchos devem respeitar as funções assíncronas e também esperar valores de retorno que são então passados ​​para a próxima função de gancho.

Vou refatorar meu código vendo que isso não está sendo honrado, mas um código feio sairá disso, já que seria um hack.

Parece-me que permitir o suporte assíncrono para os métodos de ciclo de vida irá encorajar práticas ruins de UX por padrão. Como? As funções assíncronas são usadas para solicitações que não podem ser concluídas imediatamente (por exemplo, solicitações de longa duração ou de rede). Forçar o Vue a atrasar a criação ou montagem ou qualquer um dos outros métodos de ciclo de vida para aguardar sua solicitação de rede ou processo assíncrono de longa duração afetará o usuário de maneiras perceptíveis. Imagine um usuário acessando seu site e tendo que esperar 4 segundos com uma tela em branco enquanto o componente espera que a conexão de célula irregular do usuário conclua sua solicitação de rede. E isso não apenas afeta negativamente o usuário, mas também está sacrificando seu controle sobre a situação - não há nada que você possa fazer como desenvolvedor para tornar o tempo de carregamento percebido pelos usuários mais rápido ou mostrar indicadores de progresso determinados ou indeterminados. Portanto, ao construir essa capacidade no Vue, você não está tornando a web um lugar melhor; você está habilitando práticas inadequadas.

É muito melhor planejar e projetar para o caso assíncrono desde o início: inicie seu processo assíncrono em created ou mounted ou qualquer outro lugar e, em seguida, faça com que seu componente tenha uma estrutura de esqueleto ou, na pior das hipóteses um botão giratório enquanto você espera que sua API retorne as permissões do usuário. UX muito melhor e você não sacrifica nenhum controle. E o Vue não precisa adicionar código para lidar com funções de ciclo de vida assíncronas, mantendo o pacote menor. Vitória, vitória.

Uma opinião de milhares. Só porque você não pode imaginar um cenário em que a renderização do componente sendo atrasada pode conviver com uma experiência positiva do usuário, não significa que ela não exista.

Se um framework luta contra o desenvolvedor, o desenvolvedor encontrará outro framework.

@ robob4him

Uma opinião de milhares. Só porque você não pode imaginar um cenário em que a renderização do componente sendo atrasada pode conviver com uma experiência positiva do usuário, não significa que ela não exista.

Se um framework luta contra o desenvolvedor, o desenvolvedor encontrará outro framework

Você está absolutamente certo, mas nada do que compartilhou aqui é um argumento válido para resolver o problema de uma forma ou de outra. Você introduziu uma tática de intimidação para coagir a comunidade a desenvolver um recurso. Não é uma continuação construtiva da conversa.

@wparad , é uma tática absolutamente assustadora, mas não vai coagir ninguém a fazer nada. Apresentar argumentos de que um recurso oferece suporte a hábitos ruins ou antipadrões ou prejudicará a comunidade maior de desenvolvedores é uma tática assustadora.

Metade dos recursos de literalmente qualquer framework / linguagem são perigosos para o desenvolvedor; métodos públicos podem ser estendidos, Vue incentiva o acesso ao elemento ($ el), etc. Frameworks fornecem essas coisas porque, no final do dia, o desenvolvedor precisa fazer o trabalho.

Este pedido de recurso tem um ano. As pessoas devem entender que o motivo não é realmente porque isso causaria práticas inadequadas, nem devem perceber o atraso na renderização como uma prática inadequada.

Eu preciso usar requirejs com vue. Não que eu goste de requirejs, mas porque eu quero usar o vue com um LMS de código aberto que tem todos os seus módulos como módulos AMD. Seria ótimo se eu pudesse carregar todas as libs que preciso no gancho beforeCreate. A alternativa para mim no momento é carregá-los fora do vue e depois passá-los para o que é mais confuso.

Parece-me que permitir o suporte assíncrono para os métodos de ciclo de vida irá encorajar práticas ruins de UX por padrão. Como? As funções assíncronas são usadas para solicitações que não podem ser concluídas imediatamente (por exemplo, solicitações de longa duração ou de rede). Forçar o Vue a atrasar a criação ou montagem ou qualquer um dos outros métodos de ciclo de vida para aguardar sua solicitação de rede ou processo assíncrono de longa duração afetará o usuário de maneiras perceptíveis. Imagine um usuário acessando seu site e tendo que esperar 4 segundos com uma tela em branco enquanto o componente espera que a conexão de célula irregular do usuário conclua sua solicitação de rede. E isso não apenas afeta negativamente o usuário, mas também está sacrificando seu controle sobre a situação - não há nada que você possa fazer como desenvolvedor para tornar o tempo de carregamento percebido pelos usuários mais rápido ou mostrar indicadores de progresso determinados ou indeterminados. Portanto, ao construir essa capacidade no Vue, você não está tornando a web um lugar melhor; você está habilitando práticas inadequadas.

É muito melhor planejar e projetar para o caso assíncrono desde o início: inicie seu processo assíncrono em created ou mounted ou qualquer outro lugar e, em seguida, faça com que seu componente tenha uma estrutura de esqueleto ou, na pior das hipóteses um botão giratório enquanto você espera que sua API retorne as permissões do usuário. UX muito melhor e você não sacrifica nenhum controle. E o Vue não precisa adicionar código para lidar com funções de ciclo de vida assíncronas, mantendo o pacote menor. Vitória, vitória.

O que você está dizendo é como adicionar v-if/v-clock/v-show recursos irá encorajar práticas inadequadas, portanto, é melhor tornar a estrutura à prova de idiotas removendo esses recursos. Em seguida, use alguma abordagem complicada para fazer o mesmo, de modo que Vue seja menor por não colocar essas 3 diretivas. Os primeiros desenvolvedores não são estúpidos. A segunda prova de erros do framework, por sua vez, limita sua usabilidade porque você está limitando o que pode ser feito com base em aparentes "tolos". Por que alguém colocaria v-if em todo o site para bloqueá-lo por meio de operações assíncronas, deixando a tela inteira em branco?

Acho que você está ignorando o fato de que a maioria dos casos de uso pode nem estar com uma página em branco. Eles são chamados de componentes por um motivo. Casos em que eu pessoalmente desejo usar isso é quando algo já está na tela fazendo outra coisa. Este pode ser um componente bloqueado por v-if por exemplo e disparado quando algo muda. No entanto, no processo de renderização pela primeira vez, async functions etc precisa ser respeitado enquanto o componente é inicializado. Eu vasculhei toda a documentação do Vue procurando por isso e finalmente fiz isso com uma solução alternativa não tão bonita como os exemplos hackeados acima.

O que me preocupa é alguém / até mais tarde eu mantendo o código. É como o inferno de callback Promise vs Async ... Await.

Na verdade, vejo que está melhorando a flexibilidade e controlabilidade do framework de uma forma fácil de acompanhar. Basta dar uma olhada nos hacks acima para ver o que quero dizer. Os desenvolvedores estão fazendo tudo isso apenas para preencher a lacuna de uma instrução async mounted () { await... } simples, por exemplo. Se você não quiser usar esses recursos, simplesmente não defina as funções como async ou mesmo use await .

Na verdade, alguém que realmente usará um gancho de ciclo de vida async mounted provavelmente entenderá o que está fazendo e por que o fará, e muito provavelmente NÃO fará essas práticas ruins que o preocupam.

@emahuni , acho que ninguém discordaria da expectativa que você está compartilhando, mas acho que há uma nuance que está sendo deixada de fora. Vamos supor que async mounted ou async created atrase o componente de ser renderizado. O que o pai faz neste caso? Isso:

  • bloquear também
  • suponha que o componente deve ser removido do DOM v-if até que o carregamento seja concluído
  • suponha que o componente deve ser escondido até o carregamento completo
  • Mostrar um elemento temporário em seu lugar?

Embora eu concorde que as expectativas em torno de um componente carregado dinamicamente são consistentes, o comportamento para o pai não acho que seria. Nesses casos, seria a IMO expor a implementação da criança aos pais e forçá-los a descobrir o que fazer com esse componente dinâmico. Em vez disso, como os dados são carregados e o estado do componente filho deve ser decidido pelo filho. Se ele carregar de forma assíncrona, será necessário explicar ao Vue o que deve ser renderizado em seu lugar (ou não renderizado). A melhor maneira de lidar com isso é como a estrutura já funciona, em vez de introduzir uma nova complexidade.

Além disso, não estou totalmente seguindo seu argumento:

O que você está dizendo é como adicionar recursos v-if / v-clock / v-show irá encorajar práticas ruins, então é melhor tornar a estrutura à prova de idiotas removendo esses recursos

Embora, neste caso, podemos ver claramente que componentes assíncronos introduzindo aguardando a montar ou criado fará com que as más práticas, não é claro que isso faz. Em segundo lugar, é uma petição inicial, mesmo que causem práticas inadequadas, devemos optar por corrigi-los , em vez de usá-los como justificativa para criar novas práticas inadequadas. Se você souber de más práticas que estão sendo criadas por v-if , etc ... Convido você a compartilhar explicitamente (em outra edição, é claro) qual é o problema com elas, em vez de tentar usar isso como uma justificativa para uma discussão diferente.

@emahuni , acho que ninguém discordaria da expectativa que você está compartilhando, mas acho que há uma nuance que está sendo deixada de fora. Vamos supor que async mounted ou async created atrase o componente de ser renderizado. O que o pai faz neste caso? Isso:

  • bloquear também

O pai pode prosseguir e renderizar sem nem mesmo esperar pela criança, por que deveria? Ele pode ir em frente e executar updated assim que a criança tiver renderizado.

  • suponha que o componente deve ser removido do DOM v-if até que o carregamento seja concluído

Não tenho certeza se entendi ... mas a resposta é não, não presumimos que será removido, ele só precisa fazer algo durante a montagem que deve ser bloqueada durante esse tempo. Existem muitos casos de uso lidos acima para isso.

  • suponha que o componente deve ser escondido até o carregamento completo

Isso depende do desenvolvedor, por que eles estão sincronizando o gancho montado ou qualquer outro gancho para esse assunto.

  • Mostrar um elemento temporário em seu lugar?

Isso pode não ser o caso. Novamente, depende do desenvolvedor o que ele pretende alcançar. O que quero dizer é que nada deve ser uma camisa de força. Quando, por exemplo, v-if foi projetado, não foi porque eles conceberam por que alguém iria querer bloquear a renderização de um componente a cada vez, e o que eles colocaram em vez disso e o tornaram à prova de falhas. Existem muitas coisas que podem dar errado com v-if pelo design do desenvolvedor. Você não deve se preocupar com o que estará na tela durante esse tempo, não é para o framework se preocupar.

Embora eu concorde que as expectativas em torno de um componente carregado dinamicamente são consistentes, o comportamento para o pai não acho que seria. Nesses casos, seria a IMO expor a implementação da criança aos pais e forçá-los a descobrir o que fazer com esse componente dinâmico. Em vez disso, como os dados são carregados e o estado do componente filho deve ser decidido pelo filho. Se ele carregar de forma assíncrona, será necessário explicar ao Vue o que deve ser renderizado em seu lugar (ou não renderizado). A melhor maneira de lidar com isso é como a estrutura já funciona, em vez de introduzir uma nova complexidade.

Para sua informação: Você concorda que isso precisa ser implementado, no entanto, vai introduzir essas complexidades pelas quais você está chorando e ele sente que isso pode ser feito mais tarde, quando mudanças importantes forem introduzidas, e não no Vue 3. O ponto é que ele sente que é necessário .

Além disso, não estou totalmente seguindo seu argumento:

O que você está dizendo é como adicionar recursos v-if / v-clock / v-show irá encorajar práticas ruins, então é melhor tornar a estrutura à prova de idiotas removendo esses recursos

Embora, neste caso, podemos ver claramente que componentes assíncronos introduzindo aguardando a montar ou criado fará com que as más práticas, não é claro que isso faz. Em segundo lugar, é uma petição inicial, mesmo que causem práticas inadequadas, devemos optar por corrigi-los , em vez de usá-los como justificativa para criar novas práticas inadequadas. Se você souber de más práticas que estão sendo criadas por v-if , etc ... Convido você a compartilhar explicitamente (em outra edição, é claro) qual é o problema com elas, em vez de tentar usar isso como uma justificativa para uma discussão diferente.

Eu meramente apontei essas diretivas como um exemplo de recursos que podem ser usados ​​incorretamente para bloquear a renderização de um componente semelhante ao que você estava dizendo sobre async... . Nada de errado com eles. Portanto, devemos remover essas diretivas apenas porque alguém pode usar "práticas inadequadas" para criar componentes que mostram páginas em branco por um minuto? Na verdade, você não vê ninguém fazendo isso porque não acontece, a menos que esteja tentando dar um exemplo da pior maldade como em terrível.

Olha, a questão é, se você não consegue ver nenhum caso de uso ainda, então não diga que outras pessoas vão usá-lo mal e, portanto, não deve ser feito. A má prática é uma questão de ignorância e alguém tão ignorante pode nunca usar esses recursos completamente.

Alguém perguntou isso https://github.com/vuejs/vue/issues/7209#issuecomment -424349370 lá em cima e ninguém respondeu até onde eu vi. Isso está de longe mostrando genuinamente que a Vue está ficando para trás nessa parte. Esta parte da arquitetura foi projetada quando o assíncrono ainda não existia. Portanto, atualizá-lo para atender aos requisitos modernos de arquiteturas modernas é com certeza uma boa ideia. Caso contrário, o resto são truques e soluções alternativas que precisam de maneiras específicas de fazer isso, em vez de fazer o que está acontecendo na indústria.

No entanto, ainda não tenho certeza, mas olhando rapidamente para a nova API funcional, parece que realmente é possível fazer isso. Como é funcional, significa que é possível fazer certas coisas que não poderiam objetivamente, como ganchos de ciclo de vida assíncronos.

Olha, a questão é, se você não consegue ver nenhum caso de uso ainda, então não diga que outras pessoas vão usá-lo mal e, portanto, não deve ser feito. A má prática é uma questão de ignorância e alguém tão ignorante pode nunca usar esses recursos completamente.

Nunca fiz essa afirmação, estou afirmando que quero executar ações assíncronas por padrão, sem nunca bloquear a renderização do componente. Não é intuitivo que executar async ações em um bloco mounted ou created fará com que a renderização do componente seja atrasada. Supondo que fosse esse o caso, eu veria a complexidade surgir de como um consumidor, que deseja a funcionalidade atual, procederia. O argumento até agora não é que o que está sendo pedido não pode ser feito, é que o que está sendo solicitado deve ser o padrão. Você já pode bloquear a renderização de seu componente alternando o modelo exibido com base em v-if="loaded" .

Agora, para renderizar sem bloquear o código, fica assim:
No momento, esse código é:

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

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

E renderizar com bloqueio tem exatamente a mesma aparência, já que você não pode realmente bloquear. Supondo que async created() realmente bloqueou o componente. Então agora temos uma separação de código. Para exibir o spinner, escrevemos:

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

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

e simplesmente ignorar a renderização do componente na tela que escrevemos

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

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

Para qual benefício adicionar esta simplificação para bloquear a garantia de renderização torna o bloqueio não mais complicado? Eu simplesmente não estou vendo isso.

Tratamento de dependências para componentes

@ yyx990803 Por favor, dê uma olhada nisto, não é perfeito, mas mesmo assim é um cenário de caso de uso complexo.

Ok, aqui está um caso de uso que poderia ter sido tratado elegantemente se os ganchos de ciclo de vida tivessem assíncronos ... await:
_Eu realmente queria fazer isso em um aplicativo e obtive um código feio para fazer isso. Este é um exemplo muito artificial de coz_

Preciso que o componente A aguarde os ganchos mounted componente B && C antes de montar. Portanto, mounted componente A tem que aguardar seu gancho created , que acionou a montagem do componente B && C que estava esperando pelo gatilho _ (que pode realmente fazer algo antes de esperar) _. O fato é que é mais fácil dessa maneira e muito mais limpo e intuitivo, pois tudo permanece em um lugar para o componente em questão.

A emite um evento de disparo e ouve respostas de B e C _ (B e C de espera para o sinal de 's Uma antes de continuar, eventos, em seguida, emitem uma vez montado) _ antes de continuar, simples. Isso é mais como um cenário de dependência para componentes sem quaisquer dados estranhos espalhados em outro lugar para gerenciamento de estado.

Principal componente de hospedagem , todos os componentes são carregados juntos, mas espere pelos corretos usando eventos e assíncronos ... aguarde. Não importa o que essas crianças façam, elas se auto-ordenam.

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

o componente A controla a montagem de B e C como dependências. O acionamento pode ser feito posteriormente em outros ganchos ou até mesmo por meio de um evento UX dos mesmos componentes. O que se segue é apenas para mostrar a ideia aqui.

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

O código acima pode ser simplificado ainda mais por mixins, visto que há muitos trechos de código duplicados, eu só queria que ficasse claro. O método wasMounted pode ser enlatado em um mixin e usado em todos os 3 componentes.

Aqui podemos ver claramente o que cada componente está esperando, sem qualquer outro código hackish ou de roteador espalhado em outro lugar para controlar exatamente a mesma coisa. É muito confuso fazer isso sem esse recurso, acredite, eu fiz isso em um aplicativo.

Isso obviamente elimina códigos desnecessariamente complexos e impossíveis de manter.

Agora imagine isso em um aplicativo grande, com 32 componentes do propulsor que se comportam de maneira diferente. Você terá apenas cerca de 3 pontos em mente, que podem ser reduzidos a até 2 se você adicionar mixins.

Fazendo as coisas ficarem frescas

Claro que isso não se limita apenas a montado e criado, mas na verdade deve funcionar com todos os outros ganchos de ciclo de vida. Imagine se isso fosse um novo gancho beforeActivate / beforeUpdate . Poderíamos fazer o componente aguardar _ativação / atualização_ e apenas _ativar / atualizar_ quando a atualização for feita cada vez que o componente for _ativado / atualizado_; certificando-se de que as coisas continuem atualizadas.

A lista é interminável depois que isso é implementado.

Olha, a questão é, se você não consegue ver nenhum caso de uso ainda, então não diga que outras pessoas vão usá-lo mal e, portanto, não deve ser feito. A má prática é uma questão de ignorância e alguém tão ignorante pode nunca usar esses recursos completamente.

Nunca fiz essa afirmação, estou afirmando que quero executar ações assíncronas por padrão, sem nunca bloquear a renderização do componente. Não é intuitivo que executar async ações em um bloco mounted ou created fará com que a renderização do componente seja atrasada. Supondo que fosse esse o caso, eu veria a complexidade surgir de como um consumidor, que deseja a funcionalidade atual, procederia. O argumento até agora não é que o que está sendo pedido não pode ser feito, é que o que está sendo solicitado deve ser o padrão. Você já pode bloquear a renderização de seu componente alternando o modelo exibido com base em v-if="loaded" .

Agora, para renderizar sem bloquear o código, fica assim:
No momento, esse código é:

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

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

E renderizar com bloqueio tem exatamente a mesma aparência, já que você não pode realmente bloquear. Supondo que async created() realmente bloqueou o componente. Então agora temos uma separação de código. Para exibir o spinner, escrevemos:

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

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

e simplesmente ignorar a renderização do componente na tela que escrevemos

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

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

Para qual benefício adicionar esta simplificação para bloquear a garantia de renderização torna o bloqueio não mais complicado? Eu simplesmente não estou vendo isso.

Este é o bootcamp do Vue 101 e não há nada de novo aí ... não é suficiente para cobrir os casos acima, por exemplo. A ideia aqui é reduzir a complexidade na área do usuário onde o Vue é realmente usado e disponibilizar um código mais fácil de raciocinar.

A renderização aqui não é o problema, é o que está acontecendo antes da renderização que é realmente importante. Queremos liberdade para fazer as coisas antes de prosseguir ou renderizar um componente. De qualquer forma, isso também não tem nada a ver com o bloqueio da renderização. Existem muitos ganchos de ciclo de vida que o Vue suporta e eles podem realmente ser úteis se houver uma maneira de lidar com o código assíncrono em outros ganchos. A ideia é que o Vue respeite o assíncrono internamente antes de ir para a próxima função de gancho.

Estou realmente confuso com isso, em vez de acoplar B & C a A, eu moveria o código para "carregar A" em A.js e, em seguida, faria A.js atualizar "B.data" e "C.data" . Dessa forma, se o A.data mudar por qualquer motivo, os outros componentes serão automaticamente renderizados em vez de tentar delegar
controle de um componente para outro. Mesmo no caso compartilhado, eu ainda separaria os dados para renderizar A do componente A. Usamos uma única classe que contém métodos como fetchData e hasInitialized, para os quais o último é uma promessa e o primeiro resolve o último.
O acoplamento direto dos componentes cria árvores de dependências inesperadas que evitam que os componentes sejam reutilizáveis ​​e permitem que o vue os processe novamente corretamente.

Alternativamente, eu até mesmo emit o evento diretamente para o pai de A, B e C, e não no escopo global, e deixaria o pai decidir se renderizar B e C, ou seja,

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

O que há com A que, neste caso, precisaríamos realmente renderizar antes que B e C sejam renderizados. Se houver algo no método created() , nada impede que isso povoe a loja por meio de uma classe javascript ou usando um módulo store . Mas o caso de uso explícito seria mais útil, ou seja, qual é o UX da história do usuário que não pode ser capturado?

A ideia é que o Vue respeite o assíncrono internamente antes de ir para a próxima função de gancho.

Claro que essa parte faz sentido, mas não sei por que o exemplo precisa ser complicado, por que não apenas dizer algo como esta história de usuário:

Meu componente tem async beforeMount e async mounted , mas o código em mounted está disparando antes que o código em beforeMount seja concluído. Como podemos impedir que mounted seja disparado antes que beforeMount seja concluído?

Que é mais ou menos o que a solicitação original era, então a pergunta que foi levantada na segunda resposta eu acho que ainda é relevante: https://github.com/vuejs/vue/issues/7209#issuecomment -350284784

Encerrando por enquanto, mas fique à vontade para continuar com raciocínios / casos de uso / implicações mais concretos.

Existe realmente um caso de uso válido para a necessidade de bloquear em ganchos de ciclo de vida executados anteriormente ou é correto que os ganchos de ciclo de vida sejam síncronos. Até agora, a discussão tem sido de natureza filosófica (como as boas discussões sobre arquitetura tendem a fazer), mas na verdade a questão é se realmente houve um bom motivo para fazer isso. Não tenho dúvidas de que é razoável para o framework aguardar o código assíncrono. Eu tive o mesmo problema em N outras bibliotecas que não faziam isso ou passavam um callback (ou passavam um callback, mas não passavam um callback para o callback). No entanto, é realmente razoável ter um gancho de ciclo de vida assíncrono ou as razões são o resultado de tentar fazer algo que "não deveria ser feito"?

Ou seja, o que acontece quando você tenta unmount um componente que não acabou de ser created , uau, seria ruim estar esperando por isso ainda. Ou destroying one que não acabou de ser mounted , não invejo o implementador dessa funcionalidade.

Estou realmente confuso com isso, em vez de acoplar B & C a A, eu moveria o código para "carregar A" em A.js e, em seguida, faria A.js atualizar "B.data" e "C.data" . Dessa forma, se o A.data mudar por qualquer motivo, os outros componentes serão automaticamente renderizados em vez de tentar delegar

Isso aumentou a complexidade, prática ruim. Tente escrever aqui na íntegra, vamos ver o que você quer dizer, mas para mim você apenas aumentou muito a complexidade.

controle de um componente para outro. Mesmo no caso compartilhado, eu ainda separaria os dados para renderizar A do componente A. Usamos uma única classe que contém métodos como fetchData e hasInitialized, para os quais o último é uma promessa e o primeiro resolve o último.

Isso agora está acoplando demais os componentes. Queremos que funcionem sem o outro, exceto o A.

O acoplamento direto dos componentes cria árvores de dependências inesperadas que evitam que os componentes sejam reutilizáveis ​​e permitem que o vue os processe novamente corretamente.

Na verdade, você está perdendo o ponto, eles são fracamente acoplados ao ponto de que cada um pode ser usado e mantido sem afetar o outro. Na verdade, você pode soltar qualquer um deles várias vezes em qualquer lugar sem escrever mais nenhum código nos pais fora de <component-x /> , sem v-if , vuex para gerenciar seu estado nem qualquer outra coisa.

Eu os acoplei A a B e C apenas para demonstrar, eu poderia ter dividido isso bem ou apenas contar quantos componentes responderam e continuar quando um determinado número esperado for alcançado (2 neste caso), por exemplo:

 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

Enfim, é por isso que eu disse Gerenciamento de Dependências de Componentes, isso é desejado e esperado, mas deve ser feito com o mínimo de complexidade possível porque quanto mais complexo fica mais confuso se torna.

Alternativamente, eu até mesmo emit o evento diretamente para o pai de A, B e C, e não no escopo global, e deixaria o pai decidir se renderizar B e C, ou seja,

Eu sabia que você ia dizer isso, mas isso é indesejado. Esses componentes não devem ser controlados por mais nada, por isso enfatizei que o componente principal se importa menos com o que seus filhos fazem, eles devem permanecer independentes. Quero poder colocá-los em qualquer lugar do aplicativo e ainda fazer a mesma coisa funcionar . No momento em que você faz o que está dizendo ali, observe como tudo se desintegra. Mas posso facilmente colocar componentes literalmente em qualquer lugar da árvore DOM sem nem mesmo pestanejar, e tudo vai funcionar. Posso até ter várias cópias disso e ainda funcionará. Tudo graças a async ... await nos ciclos de vida.

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

O que há com A que, neste caso, precisaríamos realmente renderizar antes que B e C sejam renderizados.

Queremos que cada componente faça um trabalho exclusivo antes de ser montado. Mas todos os componentes só serão renderizados quando todos os outros componentes tiverem terminado de fazer esse trabalho. Essa é a história aqui.
Portanto, boa sorte com o gerenciamento de estado e v-if apenas para controlar isso, sem mencionar os dados reais que provavelmente produzirá no armazenamento vuex . Você acabará tendo uma grande quantidade de código duplicado escrito onde quer que o componente seja usado. Digamos que você tenha outro componente que hospeda apenas A e C e em uma configuração diferente? Você tem que escrever aqueles v-if 's, gerenciamento de estado vuex para fazer isso funcionar. Você vê o problema? deixe-me 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 ...,
}

..... e assim por diante

em vez de apenas usar os componentes sem nunca fazer nada nos pais, como:

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

... e assim por diante

Se houver algo no método created() , nada impede que isso povoe a loja por meio de uma classe javascript ou usando um módulo store . Mas o caso de uso explícito seria mais útil, ou seja, qual é o UX da história do usuário que não pode ser capturado?

Lembra do que eu disse sobre a gestão do estado espalhada por toda parte? Não queremos que o gerenciamento desses componentes signifique que estaremos gerenciando muitas coisas em outro lugar, o que é muito complexo em vez do que acabei de fazer. Além disso, não vai fazer o que eu quero; apenas monte quando cada componente tiver concluído o que deveria fazer com muito pouca complexidade.

A ideia é que o Vue respeite o assíncrono internamente antes de ir para a próxima função de gancho.

Claro que essa parte faz sentido, mas não sei por que o exemplo precisa ser complicado, por que não apenas dizer algo como esta história de usuário:

Meu componente tem async beforeMount e async mounted , mas o código em mounted está disparando antes que o código em beforeMount seja concluído. Como podemos impedir que mounted seja disparado antes que beforeMount seja concluído?

O que queremos é que as coisas aconteçam antes que qualquer um desses componentes seja renderizado e possa ser usado sem muita entrada fora dos próprios componentes. Isso é algo que percebi que poderia ter feito melhor se estivesse disponível um aplicativo que estamos fazendo. Acabei escrevendo um código que tem muitos mixins, vuex e pais fortemente acoplados em todos os lugares (usando mixins) os componentes foram usados ​​porque isso está faltando. Esta não é uma história complicada, na verdade estou contando o que aconteceu de uma maneira simples. Tivemos que repensar como a IU deveria ser projetada e mantida. Ele ficou um pouco menos interessante visualmente e muito complexo em termos de código.

Você vê quantas coisas complexas você introduziu nesta configuração simples que acabou de ser resolvida por aquele pequeno recurso assíncrono ... aguarda em ciclos de vida?

@wparad

Ou seja, o que acontece quando você tenta desmontar um componente que ainda não terminou de ser criado, nossa, que seria ruim ficar esperando por isso ainda. Ou destruindo um que não terminou de ser montado, não invejo o implementador dessa funcionalidade.

É aqui que:

... requer um repensar / reescrever fundamentalmente a arquitetura para ser alcançado, e pode quebrar muitas lógicas que dependem da natureza síncrona dos ganchos do ciclo de vida ...

... parte eu acredito que foi mencionada por você. Precisamos de uma maneira de lidar com esses casos extremos e provavelmente mais do que isso apresenta. Em outras palavras, nossas intenções devem funcionar sem travar o aplicativo.

Em todos esses casos, eu usaria o tempo limite para verificar ou abortar a espera, assim como a maioria das operações assíncronas que podem falhar.

Mas se você olhar o exemplo que apresentei cuidadosamente, você verá o que quero dizer. Isso poderia ter resolvido muitas coisas, sem muito código escrito em qualquer lugar. Na verdade, nosso aplicativo poderia ter sido muito melhor com uma base de código muito pequena, desfragmentada e fácil de entender, se isso fosse possível.
O problema com esse tipo de recurso é que você só vê sua importância depois de encontrar um obstáculo. Cheguei a esta página pela primeira vez quando pensamos em muitas soluções alternativas para esse exemplo que acabei de dar. Não vim pedir ajuda, era para apresentar um pedido de recurso, pois percebemos que não estava disponível no Vue.

Esta página foi útil?
0 / 5 - 0 avaliações