O meu maior desafio durante o desenvolvimento de um Shiny app complexo é a construção do fluxo de reatividade. Não foram raras as vezes que gastei horas pensando em uma lógica de programação que gerasse o comportamento que eu gostaria ou que simplesmente fizesse o app funcionar.
Além de a reatividade ser um conceito abstrato e invisível no código, precisamos não apenas garantir que o app funcione, mas também que funcione adequadamente. Se ao mudar o valor de um slider, por exemplo, a gente espera que um gráfico seja atualizado, dois problemas podem surgir: (1) o gráfico não ser recalculado e (2) o gráfico ser recalculado mais de uma vez.
Os dois problemas indicam um fluxo de reatividade mal construído. A diferença é que no primeiro caso o app não funciona e no segundo ele funciona de maneira inadequada.
Para evitar esses problemas, podemos imaginar ou desenhar o fluxo de reatividade para investigar onde está a falha. Essa é uma tarefa simples em apps com poucos inputs e outputs, mas extremamente difícil ou inviável em apps complexos.
Nesses casos, ou mesmo nos casos simples, podemos utilizar o pacote reactlog
. Com ele, além de criarmos facilmente o diagrama do fluxo de reatividade de qualquer Shiny app, podemos olhar o que acontece por trás das curtinas da reatividade quando executamos o aplicativo.
Antes de mais nada, instale o pacote reactlog
.
install.packages("reactlog")
Em seguida, no Console, rode o código abaixo. Isso vai habilitar o reactlog
para qualquer app que você rodar na sessão de R atual.
options(shiny.reactlog = TRUE)
Por fim, rode o seu app e utilize o comando CTRL + F3
(no Mac, command + F3
). O seu navegador abrirá uma nova aba com o diagrama de reatividade. Veja o exemplo a seguir. Primeiro temos a UI de um aplicativo que gera o histograma de uma amostra com distribuição normal. O tamanho da amostra é determinado pelo sliderInput.
Sempre que o tamanho da amostra muda, o gráfico é recalculado.
Veja agora o diagrama de reatividade associado a esse app. A forma dos 4 elementos mais a esquerda representa inputs ou valores reativos, a forma do elemento plotObj
representa expressões reativas e a forma do elemento output$hist
representa os outputs (ou observadores).
Parece muito mais complicado do que deveria, né? Acontece que além do input e output, o diagrama também apresenta elementos referentes ao tamanho da janela da pessoa que está utilizando o app. Esses elementos influenciam na imagem produzida para o gráfico dentro do HTML, que é redimensionada a depender do tamanho da tela. Por isso a existência do elemento intermediário plotObj
, que guarda as instruções para gerar o gráfico criadas pelo código R. Assim, o código R no servidor não precisa ser rodado novamente para que a imagem do gráfico seja redimensionada.
Podemos filtrar o diagrama para mostrar apenas o fluxo relacionado aos inputs do aplicativo escrevendo input
no campo de busca. Repare também que os comandos no canto superior esquerdo permitem visualizar o fluxo de reatividade das ações realizadas entre a inicialização do app e o momento em que criamos o diagrama (quando pressionamos CTRL + F3).
Em resumo, com um diagrama de reatividade em mãos, podemos:
ver os inputs dos quais cada output depende e não depende;
investigar porque o código de um output não é rodado ou roda duas vezes quando acionamos um input do qual ele deveria depender;
ter uma visão menos abstrada do fluxo de reatividade e entender melhor o que acontece quando executamos cada parte do nosso app.
Um ponto importante: por razões de segurança e performance, nunca habilite o reaclog
em ambientes de produção. Quando ele está habilitado, qualquer pessoal utilizando o seu app pode ver pelo menos parte do seu código fonte (que eventualmente pode conter informações sensíveis).
Você pode aprender mais sobre o funcionamento do reaclog
clicando aqui.
É isso! Dúvidas, sugestões e críticas, mande aqui nos comentários. Até a próxima!