184 lines
5.0 KiB
Markdown
184 lines
5.0 KiB
Markdown
# 🔍 PROBLEMA DE REATIVIDADE - SVELTE 5 RUNES
|
|
|
|
## 🎯 OBJETIVO
|
|
Fazer o contador decrementar visualmente de **3** → **2** → **1** 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:
|
|
```typescript
|
|
$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
|
|
```typescript
|
|
const intervalo = setInterval(() => {
|
|
segundosRestantes = segundosRestantes - 1;
|
|
}, 1000);
|
|
```
|
|
**Resultado:** Não funcionou
|
|
|
|
### ❌ Tentativa 2: `$effect` separado com `motivoNegacao`
|
|
```typescript
|
|
$effect(() => {
|
|
if (motivoNegacao === "access_denied") {
|
|
// contador aqui
|
|
}
|
|
});
|
|
```
|
|
**Resultado:** Não funcionou
|
|
|
|
### ❌ Tentativa 3: `contadorAtivo` como trigger
|
|
```typescript
|
|
$effect(() => {
|
|
if (contadorAtivo) {
|
|
// contador aqui
|
|
}
|
|
});
|
|
```
|
|
**Resultado:** Não funcionou
|
|
|
|
### ❌ Tentativa 4: `tick()` para forçar re-renderização
|
|
```typescript
|
|
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)**
|
|
```typescript
|
|
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:
|
|
```svelte
|
|
<!-- 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"
|
|
|