Pular para o conteúdo

Estado e cache

Os três lugares onde um valor pode morar numa aplicação Vitrine, e quem enxerga cada um.

O programa roda inteiro a cada interação. Sem um lugar que sobreviva, um contador voltaria a zero a cada clique. Há três, e a diferença entre eles é quem enxerga:

OndeQuem vêSome quando
V.estadouma sessãoa sessão expira
V.geraltodas as sessõeso processo termina
V.cachetodas, por argumentoo TTL vence ou é invalidado

Estado da sessão#

dataforge
V.estado.padrao("contador", 0)       // define só se ainda não existe

given V.botao("Incrementar"):
    V.estado.somar("contador")

V.texto($"Valor: {V.estado.obter("contador")}")

V.estado.padrao substitui as três linhas que todo app escreve no começo. V.estado.somar é atômico: duas abas clicando ao mesmo tempo não perdem uma das somas, o que o ler-somar-escrever à mão perderia.

ChamadaFaz
V.estado.obter(chave, padrão)
V.estado.definir(chave, valor)escreve
V.estado.padrao(chave, valor)escreve só se não existe; devolve o que vale
V.estado.somar(chave, quanto)incrementa, sem corrida
V.estado.existe(chave)yes/no
V.estado.remover(chave)apaga uma
V.estado.limpar()apaga todas
V.estado.tudo()o vault, sem as chaves internas
V.estado.id()o identificador da sessão

Estado global#

V.geral é compartilhado por todas as sessões — configuração, um contador de visitas, um modelo de ML carregado uma vez.

dataforge
V.geral.definir("versao", "1.0.0")
V.geral.somar("visitas")

Cache#

mark @V.cache sobre uma ação, e ela para de recalcular. Vale por argumento: vendas("2026-01") e vendas("2026-02") ocupam entradas diferentes.

dataforge
mark @V.cache
action vendas(mes):
    yield Banco.consultar("SELECT … WHERE mes = ?", [mes])

Com ajustes:

dataforge
mark @V.cache(validade := 300, teto := 32)
action cotacao(moeda):
    yield Http.get($"https://…/{moeda}").json()

mark @V.cache(pasta := ".cache/ibge")
action municipios():
    yield Http.get("https://…/municipios").json()
OpçãoFaz
validadesegundos até o valor vencer (TTL)
tetoquantos valores guardar; ao encher, sai o menos usado (LRU)
pastatambém grava em disco, e sobrevive a reiniciar

O teto existe porque um cache sem limite é um vazamento com outro nome: uma ação chamada com mil argumentos diferentes guardaria mil resultados e não soltaria nenhum.

Esvaziar#

dataforge
V.cache.invalidar(vendas)     // só essa ação
V.cache.invalidar()           // tudo
V.cache.estatisticas()        // acertos, erros e taxa, por ação

E vendas.sem_cache(mes) chama a ação original — é o que permite testá-la sem o cache no caminho.

Identidade do componente#

O valor de um campo sobrevive a um clique em outro lugar da página porque cada componente tem uma chave. Sem chave, ela sai do tipo, do rótulo e da posição — estável enquanto o programa não muda.

dataforge
// Dê uma chave quando a ordem dos componentes pode mudar:
cycle cliente in clientes:
    V.entrada("Observação", chave := $"obs-{cliente["id"]}")

Sem a chave explícita aqui, remover um cliente da lista faria as observações dos seguintes escorregarem uma posição.