Pular para conteúdo

Aula 18 - Gestão de Estado de Aplicação Full Stack e Caching Distribuído 🌐

Objetivo Pedagógico

Objetivo: Arquitetura de sincronização de estado entre cliente e servidor com TanStack Query (React Query), cache distribuído com Redis e invalidação por tags.


📑 1. Fundamentos Teóricos & Análise Técnica

Em aplicações Full Stack modernas, a gestão de dados transita entre duas realidades distintas: o Estado do Servidor (Server State) e o Estado do Cliente (Client State). Confundir esses dois estados em uma única store global gera dados obsoletos (stale data), problemas de sincronização e perda de performance.

A solução arquitetural de ponta divide a responsabilidade: 1. No Servidor: Implementação do padrão Cache-Aside com Redis, onde requisições frequentes de leitura consultam a memória em cache antes de tocar o banco relacional. Mutações invalidam chaves ou tags de cache correspondentes de forma atômica. 2. No Cliente: Utilização de bibliotecas de sincronização como TanStack Query (React Query). Ela atua como um coordenador inteligente que gerencia deduplicação de requisições, refetch em background quando a janela ganha foco (Window Focus Refetching), atualizações otimistas (Optimistic Updates) e expiração de dados (Stale Time).

📐 Arquitetura Conceitual & Diagrama de Fluxo

graph TD
    Client["SPA Frontend (TanStack Query)"] -->|Cache-First: staleTime 60s| ClientCache["Cache de Memória no Navegador"]
    ClientCache -->|Se Dados Obsoletos: Fetch| Gateway["API Gateway / Backend"]
    Gateway --> Redis["Redis Cache (Cache-Aside)"]
    Redis -->|Cache Hit| Gateway
    Redis -->|Cache Miss| SQL["PostgreSQL / MySQL"]
    SQL --> Redis
    style Client fill:#e1f5fe,stroke:#01579b
    style ClientCache fill:#e8f5e9,stroke:#2e7d32
    style Gateway fill:#fff3e0,stroke:#e65100
    style Redis fill:#f3e5f5,stroke:#7b1fa2

🔍 Pilares e Diretrizes Técnicas

Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Padrão Cache-Aside: O backend busca primeiro no cache rápido; se ausente, lê do banco e popula o cache. - Atualizações Otimistas (Optimistic Updates): A UI reflete a alteração do usuário instantaneamente antes da resposta do servidor, revertendo apenas em caso de erro. - Invalidação de Cache por Tags: Purga seletiva de coleções inteiras no Redis quando uma entidade é criada ou atualizada. - Deduplicação de Requisições: Múltiplos componentes solicitando o mesmo recurso acionam apenas uma requisição HTTP.


🛠️ 2. Implementação Prática em Arquitetura Full Stack e Cache Distribuído

Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:

// optimistic-mutation.ts (Atualização Otimista com TanStack Query)
import { useMutation, useQueryClient } from '@tanstack/react-query';

interface Task { id: string; title: string; completed: boolean; }

export function useToggleTask() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (task: Task) => {
      const res = await fetch(`/api/tasks/${task.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ completed: !task.completed })
      });
      if (!res.ok) throw new Error('Falha ao atualizar tarefa.');
      return res.json();
    },
    // Atualização Otimista: altera a tela antes da resposta da API!
    onMutate: async (updatedTask) => {
      await queryClient.cancelQueries({ queryKey: ['tasks'] });
      const previousTasks = queryClient.getQueryData<Task[]>(['tasks']);

      queryClient.setQueryData<Task[]>(['tasks'], (old = []) =>
        old.map(t => t.id === updatedTask.id ? { ...t, completed: !t.completed } : t)
      );

      return { previousTasks };
    },
    // Se falhar, reverte para o estado anterior
    onError: (err, task, context) => {
      if (context?.previousTasks) {
        queryClient.setQueryData(['tasks'], context.previousTasks);
      }
    },
    // Invalida e sincroniza com o servidor
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['tasks'] });
    }
  });
}

💡 Análise Passo a Passo do Código

  1. onMutate Imediato: Aplica a alteração diretamente no cache local do cliente, proporcionando sensação de resposta instantânea.
  2. onError Rollback: Se o servidor retornar erro 500, a lista é restaurada exatamente para o estado anterior.
  3. onSettled Sincronização: Garante que o estado local seja alinhado com a resposta definitiva do banco de dados.

🎯 3. Próximos Passos & Sequência Didática