TL; DR
Como um componente pai pode saber quando a renderização de cada componente filho abaixo dele foi concluída e o DOM visível ao usuário com sua versão mais atualizada?
Digamos que eu possua um componente component A
filho Grid
composto por 3x3
componentes netos. Cada um desses componentes netos busca dados de um ponto de extremidade da API repousante e se processa quando os dados ficam disponíveis.
Eu gostaria de cobrir toda a área de Component A
com um loader
espaço reservado, a ser revelado somente quando o último dos componentes da grade buscar os dados com êxito e renderizá-los, de modo que eles já estejam no DOM e possam ser visualizados.
A experiência do usuário deve ser uma transição super suave do "carregador" para uma grade totalmente preenchida sem tremer.
Meu problema é saber exatamente quando desvendar os componentes sob o carregador.
Existe algum mecanismo em que eu possa confiar para fazer isso com precisão absoluta? Não codifico um limite de tempo para o carregador. Pelo que entendi, confiar em ComponentDidMount
todas as crianças também não é confiável, pois na verdade não garante que o componente esteja totalmente visível para o usuário no momento da chamada.
Para destilar ainda mais a questão:
Eu tenho um componente que renderiza algum tipo de dados. Depois de inicializado, ele não o possui; portanto
componentDidMount
, atinge um ponto de extremidade da API. Depois de receber os dados, ele muda de estado para refleti-los. Isso, compreensivelmente, causa uma nova renderização do estado final desse componente. Minha pergunta é a seguinte: como sei quando essa nova renderização ocorreu e se reflete no usuário que está enfrentando o DOM. Esse ponto no tempo! = O ponto no tempo em que o estado do componente mudou para conter dados.
ComponentDidMount
que estou usandoaxios
para buscar dados. quando os dados chegam, altero o estado desse componente que causa uma renderização dos dados. Em teoria, 8 componentes filhos podem ser buscados em 3 segundos e o último levaria 15 segundos ...Respostas:
Existem dois ganchos de ciclo de vida no React que são chamados após a renderização do DOM de um componente:
Para o seu caso de uso seu pai componente P está interessado quando N componentes filhos têm cada satisfeito alguma condição X . X pode ser definido como uma sequência:
Ao combinar o estado do componente e usar o
componentDidUpdate
gancho, você pode saber quando a sequência foi concluída e seu componente atende à condição X.Você pode acompanhar quando sua operação assíncrona foi concluída definindo uma variável de estado. Por exemplo:
Após definir o estado, o React chamará a
componentDidUpdate
função de componentes . Ao comparar os objetos de estado atual e anterior nessa função, você pode sinalizar para o componente pai que sua operação assíncrona foi concluída e que o estado do novo componente foi renderizado:No seu componente P, você pode usar um contador para acompanhar quantas crianças foram atualizadas significativamente:
Por fim, sabendo o tamanho de N, você pode saber quando todas as atualizações significativas ocorreram e agir de acordo com o método de renderização de P :
fonte
Eu o configuraria para que você confie em uma variável de estado global para informar seus componentes quando renderizar. O Redux é melhor para esse cenário em que muitos componentes estão conversando entre si e você mencionou em um comentário que o usa algumas vezes. Então, esboçarei uma resposta usando o Redux.
Você precisaria mover suas chamadas de API para o contêiner pai
Component A
. Se você deseja que seus netos sejam renderizados somente após a conclusão das chamadas da API, não será possível mantê-las nos próprios netos. Como uma chamada de API pode ser feita a partir de um componente que ainda não existe?Depois que todas as chamadas de API são feitas, você pode usar ações para atualizar uma variável de estado global que contém vários objetos de dados. Sempre que os dados são recebidos (ou um erro é detectado), você pode despachar uma ação para verificar se o seu objeto de dados está totalmente preenchido. Uma vez preenchido completamente, você pode atualizar uma
loading
variávelfalse
e renderizar condicionalmente seuGrid
componente.Então, por exemplo:
Seu redutor conterá o objeto de estado global, que dirá se tudo já está pronto para ser executado:
Em suas ações:
a parte, de lado
Se você é realmente casado com a ideia de que suas chamadas à API residem em cada neto, mas que toda a grade de netos não é processada até que todas as chamadas sejam concluídas, você precisará usar uma solução completamente diferente. Nesse caso, seus netos precisariam ser renderizados desde o início para fazer suas chamadas, mas terão uma classe css com
display: none
, que somente será alterada após a variável de estado globalloading
ser marcada como falsa. Isso também é possível, mas além do ponto de React.fonte
Você pode potencialmente resolver isso usando o React Suspense.
A ressalva é que não é uma boa ideia Suspender a árvore de componentes que faz a renderização (ou seja: se o seu componente iniciar um processo de renderização, não é uma boa ideia suspender esse componente, na minha experiência), por isso é provavelmente uma idéia melhor para iniciar as solicitações no componente que renderiza as células. Algo assim:
Agora, como Suspense combina com Redux, não tenho certeza. A idéia por trás dessa versão (experimental!) Do Suspense é que você inicie a busca imediatamente durante o ciclo de renderização de um componente pai e passe um objeto que represente uma busca para os filhos. Isso impede que você precise ter algum tipo de objeto Barreira (o que você precisaria em outras abordagens).
Vou dizer que não acho que esperar até que tudo tenha buscado para exibir alguma coisa seja a abordagem correta, porque a interface do usuário será tão lenta quanto a conexão mais lenta ou poderá não funcionar!
Aqui está o restante do código ausente:
E uma caixa de areia: https://codesandbox.io/s/falling-dust-b8e7s
fonte
Primeiro de tudo, o ciclo de vida pode ter um método assíncrono / aguardado.
O que precisamos saber
componentDidMount
ecomponentWillMount
,Na minha consideração, simplesmente implementá-los usando o ciclo de vida normal seria bom o suficiente.
Interface do usuário CircularProgress
Como a nova renderização do filho, fazendo com que o pai faça o mesmo, capturá-lo
didUpdate
seria bom.E, como é chamado após a renderização, as páginas não devem ser alteradas depois disso, se você definir a função de verificação como sua demanda.
Usamos essa implementação em nosso produto, que possui uma API que leva 30s a obter a resposta, tudo funcionou bem até onde eu vejo.
fonte
Quando você faz uma chamada de API
componentDidMount
, quando a chamada da API for resolvida, você terá os dados,componentDidUpdate
pois esse ciclo de vida passará por vocêprevProps
eprevState
. Então você pode fazer algo como abaixo:Se você deseja saber isso antes que o componente seja renderizado novamente, você pode usá-lo
getSnapshotBeforeUpdate
.https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate .
fonte
Existem várias abordagens que você pode seguir:
fonte