Dúvidas shiny: reatividade + módulos

Prezadxs, olá!

Estou com umas dúvidas em shiny e resolvi passar todas de uma vez em um post pra ficar mais simples de obter alguma resposta.

O contexto é uma base que recebe o ano como um filtro pra gerar um gráfico a partir de uma base filtrada. Usei a base padrão da CursoR (imdb) pra poder montar esse exemplo.

O projeto consta no seguinte link do gitthub:
maykongpedro/duvidas-shiny-apps (github.com)

Minhas dúvidas são as seguintes:

  1. Por que preciso declarar meu objeto de escolhas dentro do módulo? Se eu crio ele no script app.R e tento puxar ele no módulo, o shiny não encontra. O mesmo vale pra base, tive que colocar ela como um argumento da função server do módulo.

  2. Como uso um selectInput/sliderInput colocado dentro do sideBar de um shinyDashboard nos módulos? Ou seja, no meu exemplo quero filtrar o ano na base, usar esse input dentro do módulo. Não consegui fazer essa referência.

  3. Quando faço filtros na base para gerar gráficos ou tabelas, qual a melhor prática? Filtrar direto no renderPlot ou criar uma base_filtrada com reactive? Vi que funciona das duas maneiras porém não consegui entender perfeitamente o conceito de usar o reactive.

Os scripts seguem abaixo:

APP:

library(shiny)
library(shinydashboard)
#> 
#> Attaching package: 'shinydashboard'
#> The following object is masked from 'package:graphics':
#> 
#>     box

# Carregar base -----------------------------------------------------------
imdb <- basesCursoR::pegar_base("imdb")

# 1. Por que o objeto de escolhas gerado aqui não é encontrado pelo módulo?
# gerar escolhas
# escolhas_ano <- seq(from = 2000, to = 2010, by = 1)

# ui ----------------------------------------------------------------------
ui <- dashboardPage(
    
    # sempre nessa ordem: header -> siderbar -> body
    dashboardHeader(title = "Dúvida"),
    
    dashboardSidebar(
        
        sidebarMenu(
            menuItem(text = "Página 1", tabName = "pag1")
        )
        
        # 2. Como usar esse input aqui e ser reativo no módulo?
        # sliderInput(
        #     inputId = "ano",
        #     label = "Selecione um ano",
        #     min = min(escolhas_ano),
        #     max = max(escolhas_ano),
        #     value = max(escolhas_ano),
        #     sep = ""
        # )
        
    ),
    dashboardBody(
        tabItems(
            tabItem(
                tabName = "pag1",
                conteudo_ui("grafico")
            )
        )
    )
    
)

# server ------------------------------------------------------------------
server <- function(input, output, session) {
    
    conteudo_server("grafico", imdb)
    
}

shinyApp(ui, server)

Created on 2021-12-01 by the reprex package (v2.0.1)

Módulo

# UI ----------------------------------------------------------------------
conteudo_ui <- function(id){
    
    # 1. Por que preciso declarar as escolhas aqui e não somente no app?
    escolhas_ano <- seq(from = 2000, to = 2010, by = 1)
    
    ns <-NS(id)
    
    tagList(
        
        h2("Gráfico teste"),
        fluidRow(
            column(
                width = 3,
                
                # 2. Como uso esse input direto na sidebar?
                # colocando um input
                sliderInput(
                    inputId = ns("ano"),
                    label = "Selecione um ano",
                    min = min(escolhas_ano),
                    max = max(escolhas_ano),
                    value = max(escolhas_ano),
                    sep = ""
                )
            )
        ),
        fluidRow(
            column(
                width = 12,
                plotOutput(outputId = ns("grafico"))
            )
        )
    )
}


# Server ------------------------------------------------------------------
conteudo_server <- function(id, base){
    moduleServer(id, function(input, output, session){
        
        # browser()
        
        # 3. Filtrar a base em um reactive ou dentro do render plot?
        imdb_filtrado <- reactive({
            imdb_filtrado <- base |> 
                dplyr::filter(ano == input$ano)
        })
        
        output$grafico <- renderPlot({
            
            # 3. Filtrar a base em um reactive ou dentro do render plot?
            # imdb_filtrado <- imdb |> 
            #     dplyr::filter(ano == input$ano)
            
            imdb_filtrado() |> 
                dplyr::group_by(nota_imdb) |> 
                dplyr::summarise(receita_tot = sum(receita, na.rm = TRUE)) |> 
                ggplot2::ggplot() +
                ggplot2::geom_point(
                    ggplot2::aes(
                        x = nota_imdb,
                        y = receita_tot
                    )
                )

        })
    })
}

Created on 2021-12-01 by the reprex package (v2.0.1)

Muito obrigado por qualquer ajuda!

Abraços.

Recebi ajuda com a resposta da 3:

Quando faço filtros na base para gerar gráficos ou tabelas, qual a melhor prática? Filtrar direto no renderPlot ou criar uma base_filtrada com reactive ? Vi que funciona das duas maneiras porém não consegui entender perfeitamente o conceito de usar o reactive.

R: Se essa base filtrada será usada em mais de um output reativo, compensa colocar a “filtragem” dela dentro de um reactive(), pois a base será filtrada apenas uma vez e depois usada em diversos outputs.

Se esse filtro da base é diferente pra cada output ou se é gerado apenas um output, é indiferente onde é realizado essa filtragem (se dentro do render do output ou em um reactive), vira uma questão de gosto.

Aproveitar que o Will ta respondendo dúvidas de shiny haha
@wamorim Consegue me auxiliar na questão 2, por gentileza?

Oi, Maykon!

Você precisa transformar o input em uma expressão reativa

ano <- reactive({
  input$ano
})

e passar essa expressão para o módulo

conteudo_server("grafico", imdb, ano)

Dentro do módulo, você chama o valor contido na expressão ano usando a notação com parênteses: ano().