You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/pt-PT/7-bank-project/4-state-management
localizeflow[bot] 27f7371360
chore(i18n): sync translations with latest source changes (chunk 2/2, 302 changes)
7 months ago
..
README.md chore(i18n): sync translations with latest source changes (chunk 2/2, 302 changes) 7 months ago
assignment.md chore(i18n): sync translations with latest source changes (chunk 2/2, 302 changes) 7 months ago

README.md

Construir uma Aplicação Bancária Parte 4: Conceitos de Gestão de Estado

O Que Pode Fazer Nos Próximos 5 Minutos

Caminho de Arranque Rápido para Programadores Ocupados

flowchart LR
    A[⚡ 5 minutos] --> B[Diagnosticar problemas de estado]
    B --> C[Criar objeto central de estado]
    C --> D[Adicionar função updateState]
    D --> E[Ver melhorias imediatas]
  • Minuto 1: Testar o problema atual do estado - iniciar sessão, atualizar a página, observar o logout
  • Minuto 2: Substituir let account = null por let state = { account: null }
  • Minuto 3: Criar uma função simples updateState() para atualizações controladas
  • Minuto 4: Atualizar uma função para usar o novo padrão
  • Minuto 5: Testar a maior previsibilidade e capacidade de depuração

Teste Rápido de Diagnóstico:

// Antes: Estado disperso
let account = null; // Perdido ao atualizar!

// Depois: Estado centralizado
let state = Object.freeze({ account: null }); // Controlado e rastreável!

Porque é que isto é importante: Em 5 minutos, irá experimentar a transformação da gestão de estado caótica para padrões previsíveis e depuráveis. Esta é a base que torna as aplicações complexas geríveis.

🗺️ A Sua Jornada de Aprendizagem na Maestria da Gestão de Estado

journey
    title De Estado Disperso a Arquitectura Profissional
    section Diagnóstico de Problemas
      Identify state loss issues: 3: You
      Understand scattered updates: 4: You
      Recognize architecture needs: 6: You
    section Centralização do Controlo
      Create unified state object: 5: You
      Implement controlled updates: 7: You
      Add immutable patterns: 8: You
    section Adição de Persistência
      Implement localStorage: 6: You
      Handle serialization: 7: You
      Create session continuity: 9: You
    section Equilíbrio da Atualização
      Address data staleness: 5: You
      Build refresh systems: 8: You
      Achieve optimal balance: 9: You

Destino da Sua Jornada: No final desta lição, terá construído um sistema de gestão de estado de nível profissional que lida com persistência, frescura de dados e atualizações previsíveis - os mesmos padrões usados em aplicações de produção.

Questionário Pré-Aula

Questionário pré-aula

Introdução

A gestão de estado é como o sistema de navegação da sonda Voyager quando tudo está a funcionar bem, mal se nota que está lá. Mas quando algo corre mal, faz a diferença entre alcançar o espaço interestelar ou vaguear perdido no vazio cósmico. No desenvolvimento web, o estado representa tudo o que a sua aplicação precisa de lembrar: o estado de início de sessão do utilizador, dados de formulários, histórico de navegação e estados temporários da interface.

À medida que a sua aplicação bancária evoluiu de um simples formulário de login para uma aplicação mais sofisticada, provavelmente encontrou alguns desafios comuns. Atualize a página e os utilizadores são desconectados inesperadamente. Feche o navegador e todo o progresso desaparece. Depure um problema e está a vasculhar múltiplas funções que todas modificam os mesmos dados de maneiras diferentes.

Isto não são sinais de código pobre são as dores de crescimento naturais que ocorrem quando as aplicações atingem determinado limiar de complexidade. Todos os programadores enfrentam estes desafios quando as suas apps passam de "prova de conceito" para "prontas para produção."

Nesta lição, vamos implementar um sistema centralizado de gestão de estado que transforma a sua aplicação bancária numa aplicação fiável e profissional. Vai aprender a gerir o fluxo de dados de forma previsível, a persistir sessões de utilizador adequadamente, e a criar a experiência suave de utilização que as aplicações web modernas exigem.

Pré-requisitos

Antes de mergulhar nos conceitos de gestão de estado, precisa de ter o seu ambiente de desenvolvimento corretamente configurado e a base da sua aplicação bancária pronta. Esta lição constrói diretamente sobre os conceitos e código das partes anteriores desta série.

Certifique-se de que tem os seguintes componentes prontos antes de avançar:

Configuração Necessária:

Testar o Seu Ambiente:

Verifique se o seu servidor API está a funcionar corretamente executando este comando no terminal:

curl http://localhost:5000/api
# -> deve retornar "Bank API v1.0.0" como resultado

O que este comando faz:

  • Envia um pedido GET ao seu servidor API local
  • Testa a ligação e verifica se o servidor responde
  • Retorna a informação da versão da API se tudo estiver a funcionar corretamente

🧠 Visão Geral da Arquitetura de Gestão de Estado

mindmap
  root((Gestão de Estado))
    Problemas Atuais
      Perda de Sessão
        Problemas com Atualização da Página
        Impacto ao Fechar o Navegador
        Problemas de Reset de Variáveis
      Atualizações Dispersas
        Múltiplos Pontos de Modificação
        Desafios na Depuração
        Comportamento Imprevisível
      Limpeza Incompleta
        Problemas no Estado de Logout
        Vazamentos de Memória
        Preocupações de Segurança
    Soluções Centralizadas
      Objeto de Estado Unificado
        Fonte Única de Verdade
        Estrutura Previsível
        Fundação Escalável
      Atualizações Controladas
        Padrões Imutáveis
        Uso de Object.freeze
        Alterações Baseadas em Funções
      Rastreio de Estado
        Gestão de Histórico
        Visibilidade na Depuração
        Auditoria de Alterações
    Estratégias de Persistência
      Integração com localStorage
        Continuidade de Sessão
        Serialização JSON
        Sincronização Automática
      Atualização dos Dados
        Atualização do Servidor
        Gestão de Dados Obsoletos
        Otimização do Equilíbrio
      Otimização do Armazenamento
        Dados Mínimos
        Foco no Desempenho
        Considerações de Segurança

Princípio Central: A gestão de estado profissional equilibra previsibilidade, persistência e desempenho para criar experiências de utilizador fiáveis que escalam de interações simples a fluxos de trabalho complexos de aplicações.


Diagnóstico dos Problemas Atuais do Estado

Como Sherlock Holmes a examinar a cena de um crime, precisamos de entender exatamente o que está a acontecer na nossa implementação atual antes de resolver o mistério das sessões de utilizador desaparecidas.

Vamos fazer um simples experimento que revela os desafios subjacentes da gestão de estado:

🧪 Experimente Este Teste Diagnóstico:

  1. Inicie sessão na sua aplicação bancária e navegue para o painel principal
  2. Atualize a página do navegador
  3. Observe o que acontece ao seu estado de login

Se for redirecionado de volta ao ecrã de login, descobriu o clássico problema de persistência de estado. Este comportamento ocorre porque a nossa implementação atual guarda dados do utilizador em variáveis JavaScript que se reiniciam a cada carregamento da página.

Problemas da Implementação Atual:

A simples variável account da nossa lição anterior cria três problemas significativos que afetam tanto a experiência do utilizador como a manutenção do código:

Problema Causa Técnica Impacto no Utilizador
Perda de Sessão Atualizar a página limpa variáveis JavaScript Os utilizadores devem autenticar-se frequentemente
Atualizações Dispersas Múltiplas funções modificam o estado diretamente A depuração torna-se mais difícil
Limpeza Incompleta Logout não limpa todas as referências do estado Potenciais problemas de segurança e privacidade

O Desafio Arquitetónico:

Como o design compartimentado do Titanic, que parecia robusto até múltiplos compartimentos encherem simultaneamente, corrigir estes problemas individualmente não resolve o problema arquitetónico subjacente. Precisamos de uma solução de gestão de estado abrangente.

💡 O que estamos realmente a tentar conseguir aqui?

Gestão de estado é realmente resolver dois enigmas fundamentais:

  1. Onde estão os meus dados?: Rastrear que informação temos e de onde vem
  2. Todos estão na mesma página?: Garantir que o que os utilizadores veem corresponde ao que realmente está a acontecer

O Nosso Plano de Acção:

Em vez de correr atrás do rabo, vamos criar um sistema centralizado de gestão de estado. Imagine uma pessoa muito organizada responsável por toda a informação importante:

Schema mostrando os fluxos de dados entre o HTML, ações do utilizador e estado

flowchart TD
    A[Ação do Utilizador] --> B[Manipulador de Evento]
    B --> C[Função updateState]
    C --> D{Validação do Estado}
    D -->|Válido| E[Criar Novo Estado]
    D -->|Inválido| F[Gestão de Erros]
    E --> G[Object.freeze]
    G --> H[Atualizar localStorage]
    H --> I[Disparar Atualização da UI]
    I --> J[Utilizador Vê Alterações]
    F --> K[Utilizador Vê Erro]
    
    subgraph "Camada de Gestão de Estado"
        C
        E
        G
    end
    
    subgraph "Camada de Persistência"
        H
        L[localStorage]
        H -.-> L
    end

Compreender este fluxo de dados:

  • Centraliza todo o estado da aplicação num único local
  • Encaminha todas as alterações de estado através de funções controladas
  • Garante que a UI se mantém sincronizada com o estado atual
  • Fornece um padrão claro e previsível para gestão de dados

💡 Perspetiva Profissional: Esta lição foca-se nos conceitos fundamentais. Para aplicações complexas, bibliotecas como Redux fornecem funcionalidades de gestão de estado mais avançadas. Perceber estes princípios essenciais ajudará a dominar qualquer biblioteca de gestão de estado.

⚠️ Tópico Avançado: Não cobriremos atualizações automáticas da UI disparadas por alterações de estado, pois isto envolve conceitos de Programação Reativa. Considere isto como um excelente próximo passo na sua jornada de aprendizagem!

Tarefa: Centralizar a Estrutura de Estado

Vamos começar a transformar a nossa gestão de estado dispersa num sistema centralizado. Este primeiro passo estabelece a base para todas as melhorias que se seguem.

Passo 1: Criar um Objeto Central de Estado

Substitua a simples declaração account:

let account = null;

Por um objeto de estado estruturado:

let state = {
  account: null
};

Porque é que esta alteração importa:

  • Centraliza todos os dados da aplicação num único local
  • Prepara a estrutura para adicionar mais propriedades de estado futuramente
  • Cria uma fronteira clara entre o estado e outras variáveis
  • Estabelece um padrão que escala à medida que a sua aplicação cresce

Passo 2: Atualizar os Padrões de Acesso ao Estado

Atualize as suas funções para usar a nova estrutura de estado:

Nas funções register() e login(), substitua:

account = ...

Por:

state.account = ...

Na função updateDashboard(), adicione esta linha no topo:

const account = state.account;

O que estas atualizações alcançam:

  • Mantêm a funcionalidade existente enquanto melhoram a estrutura
  • Preparam o seu código para uma gestão de estado mais sofisticada
  • Criam padrões consistentes para aceder aos dados do estado
  • Estabelecem a base para atualizações centralizadas do estado

💡 Nota: Esta refatoração não resolve imediatamente os nossos problemas, mas cria a base essencial para as melhorias poderosas que se seguem!

🎯 Verificação Pedagógica: Princípios de Centralização

Pausa e Reflita: Acabou de implementar a base da gestão de estado centralizada. Esta é uma decisão arquitetónica crucial.

Autoavaliação rápida:

  • Consegue explicar porque é que centralizar o estado num objeto é melhor do que usar variáveis dispersas?
  • O que aconteceria se esquecesse de atualizar uma função para usar state.account?
  • Como é que este padrão prepara o seu código para funcionalidades mais avançadas?

Conexão ao Mundo Real: O padrão de centralização que aprendeu é a base de frameworks modernos como Redux, Vuex e React Context. Está a construir o mesmo pensamento arquitetónico usado em grandes aplicações.

Pergunta Desafio: Se precisasse de adicionar preferências do utilizador (tema, língua) à sua app, onde as adicionaria na estrutura de estado? Como isto escalaria?

Implementando Atualizações Controladas do Estado

Com o nosso estado centralizado, o próximo passo envolve estabelecer mecanismos controlados para modificações de dados. Esta abordagem garante mudanças de estado previsíveis e depuração facilitada.

O princípio central assemelha-se ao controlo do tráfego aéreo: em vez de permitir que múltiplas funções modifiquem o estado de forma independente, vamos canalizar todas as alterações através de uma única função controlada. Este padrão fornece uma supervisão clara sobre quando e como as mudanças de dados ocorrem.

Gestão de Estado Imutável:

Vamos tratar o nosso objeto state como imutável, ou seja, nunca o modificamos diretamente. Em vez disso, cada alteração cria um novo objeto estado com os dados atualizados.

Embora esta abordagem possa parecer inicialmente menos eficiente comparada com modificações diretas, proporciona vantagens significativas para depuração, testes e manutenção da previsibilidade da aplicação.

Benefícios da gestão de estado imutável:

Benefício Descrição Impacto
Previsibilidade As alterações só acontecem através de funções controladas Mais fácil de depurar e testar
Registo Histórico Cada alteração cria um novo objeto estado Permite funcionalidades de desfazer/refazer
Prevenção de Efeitos Colaterais Não há modificações acidentais Evita bugs misteriosos
Otimização de Desempenho Fácil detectar quando o estado mudou realmente Permite atualizações eficientes da UI

Imutabilidade em JavaScript com Object.freeze():

JavaScript fornece Object.freeze() para impedir modificações ao objeto:

const immutableState = Object.freeze({ account: userData });
// Qualquer tentativa de modificar immutableState resultará num erro

Análise do que acontece aqui:

  • Impede atribuições ou eliminações diretas de propriedades
  • Lança exceções se tentativas de modificação forem feitas
  • Garante que alterações de estado devem passar por funções controladas
  • Cria um contrato claro sobre como o estado pode ser atualizado

💡 Aprofundamento: Saiba sobre a diferença entre objetos imutáveis superficiais e imutáveis profundos na documentação MDN. Compreender esta distinção é crucial para estruturas de estado complexas.

stateDiagram-v2
    [*] --> StateV1: Estado Inicial
    StateV1 --> StateV2: updateState('account', newData)
    StateV2 --> StateV3: updateState('account', anotherUpdate)
    StateV3 --> StateV4: updateState('preferences', userSettings)
    
    note right of StateV1
        Object.freeze()
        Imutável
        Depurável
    end note
    
    note right of StateV2
        Novo objeto criado
        Estado anterior preservado
        Alterações previsíveis
    end note

Tarefa

Vamos criar uma nova função updateState():

function updateState(property, newData) {
  state = Object.freeze({
    ...state,
    [property]: newData
  });
}

Nesta função, estamos a criar um novo objeto estado e a copiar dados do estado anterior usando o operador spread (...). Depois sobrepomos uma propriedade particular do objeto estado com os novos dados usando a notação de colchetes [property] para atribuição. Finalmente, bloqueamos o objeto para impedir modificações usando Object.freeze(). Para já, só temos a propriedade account armazenada no estado, mas com esta abordagem pode adicionar tantas propriedades quanto precisar.

Também vamos atualizar a inicialização do state para garantir que o estado inicial também está congelado:

let state = Object.freeze({
  account: null
});

Depois disso, atualize a função register substituindo a atribuição state.account = result; por:

updateState('account', result);

Faça o mesmo na função login, substituindo state.account = data; por:

updateState('account', data);

Agora aproveitamos para corrigir o problema dos dados da conta não serem apagados quando o utilizador clica em Logout.

Crie uma nova função logout():

function logout() {
  updateState('account', null);
  navigate('/login');
}

Em updateDashboard(), substitua o redirecionamento return navigate('/login'); por return logout();

Experimente registar uma nova conta, fazer logout e voltar a iniciar sessão para verificar se tudo continua a funcionar corretamente.

Dica: pode olhar para todas as alterações de estado adicionando console.log(state) no fim de updateState() e abrindo a consola nas ferramentas de desenvolvimento do seu navegador.

Implementando a Persistência de Dados

O problema de perda de sessão que identificámos antes requer uma solução de persistência que mantenha o estado do utilizador entre sessões do navegador. Isto transforma a nossa aplicação de uma experiência temporária numa ferramenta fiável e profissional.

Considere como os relógios atómicos mantêm o tempo preciso mesmo durante falhas de energia armazenando o estado crítico em memória não volátil. Da mesma forma, as aplicações web precisam de mecanismos de armazenamento persistente para preservar os dados essenciais do utilizador entre sessões do navegador e atualizações de página.

Questões Estratégicas para Persistência de Dados:

Antes de implementar a persistência, considere estes fatores críticos:

Pergunta Contexto da App Bancária Impacto na Decisão
Os dados são sensíveis? Saldo da conta, histórico de transações Escolher métodos de armazenamento seguros
Quanto tempo deverá persistir? Estado de login vs. preferências temporárias de UI Selecione a duração apropriada para o armazenamento
O servidor precisa dele? Tokens de autenticação vs. configurações de UI Determine os requisitos de partilha

Opções de armazenamento do navegador:

Os navegadores modernos fornecem vários mecanismos de armazenamento, cada um desenhado para diferentes casos de uso:

APIs principais de armazenamento:

  1. localStorage: Armazenamento persistente chave/valor

    • Persiste os dados entre sessões do navegador indefinidamente
    • Sobrevive a reinícios do navegador e do computador
    • Limitado ao domínio específico do website
    • Perfeito para preferências do utilizador e estados de login
  2. sessionStorage: Armazenamento de sessão temporário

    • Funciona de forma idêntica ao localStorage durante sessões ativas
    • Apaga-se automaticamente quando a aba do navegador é fechada
    • Ideal para dados temporários que não devem persistir
  3. HTTP Cookies: Armazenamento partilhado pelo servidor

    • Enviados automaticamente com cada pedido ao servidor
    • Perfeitos para tokens de autenticação
    • Limitados em tamanho e podem afetar o desempenho

Requisito de serialização de dados:

Tanto localStorage como sessionStorage armazenam apenas strings:

// Converter objetos em strings JSON para armazenamento
const accountData = { user: 'john', balance: 150 };
localStorage.setItem('account', JSON.stringify(accountData));

// Analisar strings JSON de volta para objetos ao recuperar
const savedAccount = JSON.parse(localStorage.getItem('account'));

Perceber a serialização:

  • Converte objetos JavaScript para strings JSON usando JSON.stringify()
  • Reconstrói objetos a partir de JSON usando JSON.parse()
  • Trata automaticamente objetos aninhados complexos e arrays
  • Falha com funções, valores indefinidos e referências circulares

💡 Opção avançada: Para aplicações offline complexas com grandes conjuntos de dados, considere a API IndexedDB. Fornece uma base de dados cliente completa, mas exige uma implementação mais complexa.

quadrantChart
    title Opções de Armazenamento no Navegador
    x-axis Baixa Complexidade --> Alta Complexidade
    y-axis Duração Curta --> Duração Longa
    
    quadrant-1 Ferramentas Profissionais
    quadrant-2 Persistência Simples
    quadrant-3 Armazenamento Temporário
    quadrant-4 Sistemas Avançados
    
    localStorage: [0.3, 0.8]
    sessionStorage: [0.2, 0.2]
    HTTP Cookies: [0.6, 0.7]
    IndexedDB: [0.9, 0.9]
    Memory Variables: [0.1, 0.1]

Tarefa: Implementar persistência com localStorage

Vamos implementar armazenamento persistente para que os utilizadores mantenham o login até efetuarem logout explícito. Usaremos o localStorage para guardar os dados da conta entre sessões do navegador.

Passo 1: Definir configuração de armazenamento

const storageKey = 'savedAccount';

O que esta constante fornece:

  • Cria um identificador consistente para os nossos dados armazenados
  • Evita erros tipográficos nas referências à chave de armazenamento
  • Facilita a alteração da chave de armazenamento, se necessário
  • Segue as melhores práticas para código sustentável

Passo 2: Adicionar persistência automática

Adicione esta linha no final da função updateState():

localStorage.setItem(storageKey, JSON.stringify(state.account));

Desconstrução do que acontece aqui:

  • Converte o objeto da conta numa string JSON para armazenamento
  • Grava os dados usando a nossa chave de armazenamento consistente
  • Executa-se automaticamente sempre que ocorrem alterações no estado
  • Garante que os dados armazenados estão sempre sincronizados com o estado atual

💡 Benefício arquitetural: Porque centralizámos todas as atualizações de estado através do updateState(), adicionar persistência exigiu apenas uma linha de código. Isto demonstra o poder de boas decisões arquitetónicas!

Passo 3: Restaurar estado ao carregar a app

Crie uma função de inicialização para restaurar os dados guardados:

function init() {
  const savedAccount = localStorage.getItem(storageKey);
  if (savedAccount) {
    updateState('account', JSON.parse(savedAccount));
  }

  // O nosso código de inicialização anterior
  window.onpopstate = () => updateRoute();
  updateRoute();
}

init();

Compreender o processo de inicialização:

  • Obtém quaisquer dados da conta previamente guardados no localStorage
  • Analisa a string JSON de volta para um objeto JavaScript
  • Atualiza o estado usando a nossa função controlada de atualização
  • Restabelece a sessão do utilizador automaticamente ao carregar a página
  • Executa-se antes das atualizações de rota para garantir que o estado está disponível

Passo 4: Otimizar rota padrão

Atualize a rota padrão para tirar proveito da persistência:

Em updateRoute(), substitua:

// Substituir: return navigate('/login');
return navigate('/dashboard');

Porque esta alteração faz sentido:

  • Aproveita eficazmente o nosso novo sistema de persistência
  • Permite que o dashboard trate as verificações de autenticação
  • Redireciona automaticamente para o login se não existir uma sessão guardada
  • Cria uma experiência de utilizador mais fluida

Testar a sua implementação:

  1. Faça login na sua aplicação bancária
  2. Atualize a página do navegador
  3. Verifique que permanece autenticado e no dashboard
  4. Feche e reabra o navegador
  5. Navegue novamente para a aplicação e confirme que continua autenticado

🎉 Conquista desbloqueada: Implementou com sucesso a gestão de estado persistente! A sua app agora comporta-se como uma aplicação web profissional.

🎯 Verificação pedagógica: Arquitetura da persistência

Compreensão arquitetural: Implementou uma camada de persistência sofisticada que equilibra a experiência do utilizador com a complexidade da gestão de dados.

Conceitos chave dominados:

  • Serialização JSON: Conversão de objetos complexos em strings armazenáveis
  • Sincronização automática: Mudanças no estado desencadeiam armazenamento persistente
  • Recuperação de sessão: Apps podem restaurar o contexto do utilizador após interrupções
  • Persistência centralizada: Uma única função de atualização controla todo o armazenamento

Ligação à indústria: Este padrão de persistência é fundamental para Progressive Web Apps (PWAs), aplicações offline-first e experiências web móveis modernas. Está a construir capacidades de nível profissional.

Questão de reflexão: Como modificaria este sistema para gerir múltiplas contas de utilizador no mesmo dispositivo? Considere as implicações de privacidade e segurança.

Equilibrar persistência com frescura dos dados

O nosso sistema de persistência mantém com sucesso as sessões de utilizador, mas introduz um novo desafio: a obsolescência dos dados. Quando vários utilizadores ou aplicações modificam os mesmos dados no servidor, a informação local em cache fica desatualizada.

Esta situação assemelha-se aos navegadores Vikings que usavam tanto cartas estelares armazenadas como observações celestes atuais. As cartas forneciam consistência, mas os navegadores precisavam de observações frescas para adaptar-se às condições mutáveis. De modo semelhante, a nossa aplicação precisa tanto do estado persistente do utilizador como dos dados atuais do servidor.

🧪 Descobrir o problema da frescura dos dados:

  1. Faça login no dashboard com a conta test
  2. Execute este comando numa consola para simular uma transação a partir de outra origem:
curl --request POST \
     --header "Content-Type: application/json" \
     --data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
     http://localhost:5000/api/accounts/test/transactions
  1. Atualize a página do dashboard no navegador
  2. Observe se vê a nova transação

O que este teste demonstra:

  • Mostra como o armazenamento local pode ficar "obsoleto" (desatualizado)
  • Simula cenários reais onde os dados mudam fora da sua app
  • Revela a tensão entre persistência e frescura dos dados

O desafio da obsolescência dos dados:

Problema Causa Impacto no utilizador
Dados obsoletos localStorage nunca expira automaticamente Os utilizadores veem informação desatualizada
Alterações no servidor Outras apps/utilizadores modificam os mesmos dados Vistas inconsistentes entre plataformas
Cache vs. realidade O cache local não corresponde ao estado servidor Má experiência do utilizador e confusão

Estratégia de solução:

Vamos implementar um padrão de "atualizar ao carregar" que equilibra os benefícios da persistência com a necessidade de dados frescos. Esta abordagem mantém a experiência fluida do utilizador garantindo a precisão dos dados.

sequenceDiagram
    participant U as User
    participant A as App
    participant L as localStorage
    participant S as Server
    
    U->>A: Abre a aplicação
    A->>L: Carregar estado guardado
    L-->>A: Retornar dados em cache
    A->>U: Mostrar interface imediatamente
    A->>S: Buscar dados atualizados
    S-->>A: Retornar dados atuais
    A->>L: Atualizar cache
    A->>U: Atualizar interface com dados novos

Tarefa: Implementar sistema de atualização de dados

Vamos criar um sistema que obtém automaticamente dados atualizados do servidor enquanto mantém os benefícios da gestão de estado persistente.

Passo 1: Criar atualizador dos dados da conta

async function updateAccountData() {
  const account = state.account;
  if (!account) {
    return logout();
  }

  const data = await getAccount(account.user);
  if (data.error) {
    return logout();
  }

  updateState('account', data);
}

Compreender a lógica desta função:

  • Verifica se um utilizador está autenticado (existe state.account)
  • Redireciona para logout se não houver sessão válida
  • Busca dados frescos da conta no servidor usando a função existente getAccount()
  • Trata erros do servidor de forma elegante fazendo logout das sessões inválidas
  • Atualiza o estado com dados frescos usando o nosso sistema controlado de atualização
  • Ativa a persistência automática no localStorage através da função updateState()

Passo 2: Criar handler de atualização do dashboard

async function refresh() {
  await updateAccountData();
  updateDashboard();
}

O que esta função de atualização alcança:

  • Coordena o processo de atualização dos dados e da UI
  • Espera que os dados frescos sejam carregados antes de atualizar o ecrã
  • Garante que o dashboard mostra a informação mais atualizada
  • Mantém uma separação limpa entre gestão de dados e atualizações da UI

Passo 3: Integrar com o sistema de rotas

Atualize a sua configuração de rotas para disparar a atualização automaticamente:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: refresh }
};

Como esta integração funciona:

  • Executa a função de atualização sempre que a rota do dashboard é carregada
  • Garante que dados frescos são sempre exibidos quando o utilizador navega para o dashboard
  • Mantém a estrutura de rota existente enquanto adiciona frescura dos dados
  • Fornece um padrão consistente para inicialização específica da rota

Testar o seu sistema de atualização de dados:

  1. Faça login na sua app bancária
  2. Execute o comando curl mencionado anteriormente para criar uma nova transação
  3. Atualize a página do dashboard ou navegue para outra página e volte
  4. Verifique se a nova transação aparece imediatamente

🎉 Equilíbrio perfeito alcançado: A sua aplicação agora combina a fluidez do estado persistente com a precisão dos dados frescos do servidor!

📈 Linha temporal da sua maestria em gestão de estado

timeline
    title Jornada Profissional de Gestão de Estado
    
    section Reconhecimento do Problema
        Diagnóstico de Problemas no Estado
            : Identificar problemas de perda de sessão
            : Compreender problemas de atualizações dispersas
            : Reconhecer necessidades arquitetónicas
    
    section Fundação da Arquitetura
        Design Centralizado do Estado
            : Criar objetos de estado unificados
            : Implementar padrões de atualização controlada
            : Estabelecer princípios imutáveis
        
        Atualizações Previsíveis
            : Dominar o uso de Object.freeze()
            : Construir sistemas fáceis de depurar
            : Criar padrões escaláveis
    
    section Domínio da Persistência
        Integração com localStorage
            : Gerir serialização JSON
            : Implementar sincronização automática
            : Criar continuidade de sessão
        
        Equilíbrio da Atualização dos Dados
            : Abordar desafios da obsolescência
            : Construir mecanismos de atualização
            : Otimizar desempenho vs precisão
    
    section Padrões Profissionais
        Sistemas Prontos para Produção
            : Implementar tratamento de erros
            : Criar arquiteturas fáceis de manter
            : Seguir as melhores práticas da indústria
        
        Capacidades Avançadas
            : Pronto para integração com frameworks
            : Preparado para necessidades complexas de estado
            : Fundação para funcionalidades em tempo real

🎓 Marco de graduação: Construiu com sucesso um sistema completo de gestão de estado usando os mesmos princípios que sustentam Redux, Vuex e outras bibliotecas profissionais de estado. Estes padrões escalam desde apps simples a aplicações empresariais.

🔄 Capacidades de nível seguinte:

  • Pronto para dominar frameworks de gestão de estado (Redux, Zustand, Pinia)
  • Preparado para implementar funcionalidades em tempo real com WebSockets
  • Equipado para construir Progressive Web Apps offline-first
  • Base estabelecida para padrões avançados como máquinas de estado e observers

Desafio GitHub Copilot Agent 🚀

Use o modo Agent para completar o seguinte desafio:

Descrição: Implemente um sistema abrangente de gestão de estado com funcionalidade de desfazer/refazer para a aplicação bancária. Este desafio ajudará a praticar conceitos avançados de gestão de estado incluindo rastreamento do histórico do estado, atualizações imutáveis e sincronização da interface do utilizador.

Prompt: Crie um sistema de gestão de estado melhorado que inclua: 1) Um array de histórico do estado que rastreie todos os estados anteriores, 2) funções de desfazer e refazer que revertam para estados anteriores, 3) botões de UI para operações de desfazer/refazer no dashboard, 4) um limite máximo de histórico de 10 estados para evitar problemas de memória, e 5) limpeza adequada do histórico quando o utilizador efetuar logout. Assegure que a funcionalidade de desfazer/refazer funciona com alterações no saldo da conta e persiste através das atualizações do navegador.

Saiba mais sobre modo agent aqui.

🚀 Desafio: Otimização do armazenamento

A sua implementação agora gere sessões de utilizador, atualização de dados e gestão de estado eficazmente. Contudo, considere se a nossa abordagem atual equilibra de forma ótima a eficiência do armazenamento com a funcionalidade.

Como mestres do xadrez que distinguem entre peças essenciais e peões expendáveis, a gestão eficaz de estado exige identificar quais dados devem persistir versus quais devem ser sempre frescos do servidor.

Análise de otimização:

Avalie a sua implementação atual do localStorage e considere estas questões estratégicas:

  • Qual é a informação mínima necessária para manter a autenticação do utilizador?
  • Quais dados mudam com frequência suficiente para que o cache local traga pouco benefício?
  • Como pode a otimização do armazenamento melhorar o desempenho sem degradar a experiência do utilizador?

Este tipo de análise arquitetónica distingue desenvolvedores experientes que consideram tanto funcionalidade como eficiência nas suas soluções.

Estratégia de implementação:

  • Identificar os dados essenciais que devem persistir (provavelmente apenas a identificação do utilizador)
  • Modificar a implementação de localStorage para guardar apenas os dados críticos da sessão
  • Garantir que dados frescos são sempre carregados do servidor nas visitas ao dashboard
  • Testar que a sua abordagem otimizada mantém a mesma experiência do utilizador

Consideração avançada:

  • Comparar as compensações entre armazenar dados completos da conta vs. apenas tokens de autenticação
  • Documentar as suas decisões e raciocínios para futuros membros da equipa

Este desafio ajudará a pensar como um desenvolvedor profissional que considera tanto a experiência do utilizador como a eficiência da aplicação. Tire o tempo que precisar para experimentar diferentes abordagens!

Quiz pós-aula

Post-lecture quiz

Trabalho prático

Implementar diálogo "Adicionar transação"

Aqui está um exemplo do resultado após completar o trabalho:

Screenshot mostrando um exemplo do diálogo "Adicionar transação"


Aviso Legal: Este documento foi traduzido utilizando o serviço de tradução automática Co-op Translator. Embora nos esforcemos pela precisão, por favor esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações erradas decorrentes da utilização desta tradução.