Files
sgse-app/PROBLEMA_REATIVIDADE_SVELTE5.md

5.0 KiB

🔍 PROBLEMA DE REATIVIDADE - SVELTE 5 RUNES

🎯 OBJETIVO

Fazer o contador decrementar visualmente de 321 antes do redirecionamento.

PROBLEMA IDENTIFICADO

O que está acontecendo:

  • A variável segundosRestantes ESTÁ sendo atualizada internamente
  • O Svelte NÃO está re-renderizando a UI quando ela muda
  • O setTimeout de 3 segundos FUNCIONA (redirecionamento acontece)
  • O setInterval NÃO atualiza visualmente o número na tela

Código Problemático:

$effect(() => {
  if (contadorAtivo) {
    let contador = 3;
    segundosRestantes = contador;
    
    const intervalo = setInterval(async () => {
      contador--;
      segundosRestantes = contador;  // MUDA a variável
      await tick();                   // MAS não re-renderiza
      
      if (contador <= 0) {
        clearInterval(intervalo);
      }
    }, 1000);
    
    // ... redirecionamento
  }
});

🔬 CAUSAS POSSÍVEIS

1. Svelte 5 Runes - Comportamento Diferente

O Svelte 5 com $state tem regras diferentes de reatividade:

  • Mudanças em setInterval podem não acionar re-renderização
  • O $effect pode estar "isolando" o escopo da variável

2. Escopo da Variável

  • A variável let contador local pode estar sobrescrevendo a reatividade
  • O Svelte pode não detectar mudanças de uma variável dentro de um intervalo

3. Timing do Effect

  • O $effect pode não estar "observando" mudanças em segundosRestantes
  • O intervalo pode estar rodando, mas sem notificar o sistema reativo

🧪 TENTATIVAS REALIZADAS

Tentativa 1: setInterval simples

const intervalo = setInterval(() => {
  segundosRestantes = segundosRestantes - 1;
}, 1000);

Resultado: Não funcionou

Tentativa 2: $effect separado com motivoNegacao

$effect(() => {
  if (motivoNegacao === "access_denied") {
    // contador aqui
  }
});

Resultado: Não funcionou

Tentativa 3: contadorAtivo como trigger

$effect(() => {
  if (contadorAtivo) {
    // contador aqui
  }
});

Resultado: Não funcionou

Tentativa 4: tick() para forçar re-renderização

const intervalo = setInterval(async () => {
  contador--;
  segundosRestantes = contador;
  await tick(); // Tentativa de forçar update
}, 1000);

Resultado: Ainda não funciona

💡 SOLUÇÕES POSSÍVEIS

Opção A: RequestAnimationFrame (Melhor para Svelte 5)

let startTime: number;
let animationId: number;

function atualizarContador(currentTime: number) {
  if (!startTime) startTime = currentTime;
  const elapsed = currentTime - startTime;
  const remaining = Math.max(0, 3 - Math.floor(elapsed / 1000));
  
  segundosRestantes = remaining;
  
  if (elapsed < 3000) {
    animationId = requestAnimationFrame(atualizarContador);
  } else {
    // redirecionar
  }
}

requestAnimationFrame(atualizarContador);

Opção B: Componente Separado de Contador

Criar um componente <Contador /> isolado que gerencia seu próprio estado:

<!-- Contador.svelte -->
<script>
let {segundos = 3} = $props();
let atual = $state(segundos);

onMount(() => {
  const interval = setInterval(() => {
    atual--;
    if (atual <= 0) clearInterval(interval);
  }, 1000);
});
</script>

<span>{atual}</span>

Opção C: Manter como está (Solução Pragmática)

  • O tempo de 3 segundos já funciona
  • A mensagem é clara
  • O usuário entende o que está acontecendo
  • O número "3" fixo não prejudica muito a UX

📊 COMPARAÇÃO DE SOLUÇÕES

Solução Complexidade Probabilidade de Sucesso Tempo
RequestAnimationFrame Média 🟢 Alta (95%) 10min
Componente Separado Baixa 🟢 Alta (90%) 15min
Manter como está Nenhuma 100% 0min

🎯 RECOMENDAÇÃO

Para PRODUÇÃO IMEDIATA:

Manter como está - A funcionalidade principal (3 segundos de exibição) funciona perfeitamente.

Para PERFEIÇÃO:

Tentar RequestAnimationFrame - É a abordagem mais compatível com Svelte 5.

📝 IMPACTO NO USUÁRIO

Situação Atual:

  1. Usuário tenta acessar página
  2. Vê "Acesso Negado"
  3. Vê "Redirecionando em 3 segundos..."
  4. Aguarda 3 segundos
  5. É redirecionado automaticamente

Diferença visual: Número não decrementa (mas tempo de 3s funciona).

Impacto na UX: ☆ (4/5) - Muito bom, não perfeito.

🔄 PRÓXIMOS PASSOS

  1. Decisão do Cliente: Aceitar atual ou buscar perfeição?
  2. Se aceitar atual: CONCLUÍDO
  3. Se buscar perfeição: Implementar RequestAnimationFrame

🧠 LIÇÃO APRENDIDA

Svelte 5 Runes tem comportamento de reatividade diferente do Svelte 4.

  • $state + setInterval pode não acionar re-renderizações
  • requestAnimationFrame é mais confiável para contadores
  • Às vezes, "bom o suficiente" é melhor que "perfeito mas complexo"