📚 Módulo 06: Frontend - Setup do React 18, Vite e Lazy Routing

Neste módulo, daremos início ao desenvolvimento do Frontend da TecLoja 03 (Repositório 2). Inicializaremos a nossa SPA utilizando o empacotador de alta performance Vite configurado com TypeScript, definiremos as interfaces de dados unificadas correspondentes aos DTOs do nosso backend e configuraremos as rotas lógicas da aplicação com o React Router utilizando divisão de código dinâmico (Lazy Loading) e Suspense.


🗺️ Client-Side Routing (SPA)

Diferente de sites tradicionais onde cada clique carrega uma nova página do servidor, a SPA captura o clique localmente e renderiza o componente necessário em tempo real.

flowchart LR
    classDef react fill:#61dafb,stroke:#20232a,stroke-width:2px,color:#000;
    
    A(Navegador URL) --> B{React Router}:::react
    B -- Rota / --> C[Renderiza Componente Catalogo]:::react
    B -- Rota /carrinho --> D[Renderiza Componente Carrinho]:::react
    B -- Rota Inexistente --> E[Redireciona para /]:::react

🛠️ 1. Inicializando o Projeto React com Vite e TypeScript

Entre em um diretório fora da pasta do seu backend para criarmos o repositório independente do frontend. Execute os comandos a seguir no seu terminal:

# 1. Gerar o projeto React 18 + TypeScript via Vite de forma automática
npm create vite@latest tecloja-frontend -- --template react-ts

# 2. Entrar na pasta do projeto
cd tecloja-frontend

# 3. Instalar as dependências essenciais de navegação e conexão
npm install react-router-dom axios

# 4. Instalar tipos adicionais e utilitários de desenvolvimento
npm install @types/node --save-dev

📄 2. Definindo as Interfaces de Tipos (TypeScript DTOs)

Para manter a consistência de comunicação entre React e a API NestJS, precisamos definir no frontend os contratos de tipos correspondentes aos dados trafegados nas requisições REST.

Crie um arquivo centralizador de tipos em src/types/index.ts:

// src/types/index.ts

export interface Categoria {
  id: number;
  nome: string;
}

export interface Produto {
  id: number;
  nome: string;
  descricao?: string;
  preco: number;
  estoque: number;
  categoriaId: number;
  categoria?: Categoria;
}

export interface UsuarioLogado {
  id: number;
  username: string;
  role: 'ADMIN' | 'USER';
  token: string;
}

export interface ItemPedidoInput {
  produtoId: number;
  quantidade: number;
}

export interface CheckoutInput {
  clienteId: number;
  itens: ItemPedidoInput[];
}

export interface ItemPedidoResponse {
  id: number;
  produtoId: number;
  quantidade: number;
  precoUnitario: number;
  produto: Produto;
}

export interface PedidoResponse {
  id: number;
  dataCriacao: string;
  status: string;
  valorTotal: number;
  clienteId: number;
  itens: ItemPedidoResponse[];
  cliente: {
    id: number;
    nome: string;
    email: string;
  };
}

🗺️ 3. Roteamento Dinâmico com React Router e Lazy Loading

No desenvolvimento de Single Page Applications (SPA), carregar todos os componentes do sistema em uma única requisição inicial degrada severamente a experiência do usuário devido ao tamanho do arquivo final.

Para otimizar o carregamento, utilizaremos as APIs nativas do React:

Abra o arquivo de inicialização do frontend src/App.tsx e configure a malha de rotas conforme abaixo:

// src/App.tsx
import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import Navbar from './components/Navbar';

// Carregamento dinâmico e assíncrono (Lazy Loading) das páginas
const Catalogo = lazy(() => import('./views/Catalogo'));
const Carrinho = lazy(() => import('./views/Carrinho'));
const Login = lazy(() => import('./views/Login'));
const AdminProdutos = lazy(() => import('./views/admin/AdminProdutos'));
const ProdutoForm = lazy(() => import('./views/admin/ProdutoForm'));

function App() {
  return (
    <BrowserRouter>
      {/* Barra de navegação global visível em todas as rotas */}
      <Navbar />
      
      <main className="container-principal">
        <Suspense fallback={<div className="loading-fallback">Carregando módulo de tela...</div>}>
          <Routes>
            {/* Rotas Públicas */}
            <Route path="/" element={<Catalogo />} />
            <Route path="/carrinho" element={<Carrinho />} />
            <Route path="/login" element={<Login />} />

            {/* Rotas Administrativas Protegidas */}
            <Route path="/admin/produtos" element={<AdminProdutos />} />
            <Route path="/admin/produtos/novo" element={<ProdutoForm />} />
            <Route path="/admin/produtos/editar/:id" element={<ProdutoForm />} />

            {/* Redirecionamento de rotas inexistentes */}
            <Route path="*" element={<Navigate to="/" replace />} />
          </Routes>
        </Suspense>
      </main>
    </BrowserRouter>
  );
}

export default App;

✅ Pré-Requisitos deste Módulo

Antes de passar para o desenvolvimento de lógicas de autenticação, axios interceptors e estilos, certifique-se de que:


🤔 Por que fizemos assim?


🔍 Checkpoint

  1. Dependências Instaladas: Verifique se as bibliotecas react-router-dom e axios foram catalogadas e salvas na seção dependencies do arquivo package.json no frontend.
  2. Servidor de Desenvolvimento Rodando: Execute npm run dev no terminal do frontend e acesse o endereço fornecido (normalmente http://localhost:5173). Garanta que a página inicial carrega perfeitamente e nenhuma falha crítica de roteamento ou compilação é exibida no painel.
  3. Contrato de Roteamento: Tente digitar manualmente caminhos públicos na URL do navegador como / ou /login e verifique se o React Router faz a transição das views sem forçar uma requisição de página completa para o servidor (sem piscar a aba do navegador).

⚠️ Erros Comuns

Erro Causa Solução
npm ERR! code ENOENT ao tentar executar comandos no terminal do projeto O comando foi executado fora da pasta de contexto raiz do repositório frontend. Certifique-se de navegar para a pasta correspondente executando cd tecloja-frontend antes de rodar os scripts do npm.
Tela branca total no navegador com erro React code crashed: A component suspended while responding to synchronous input... Os componentes importados via lazy() foram renderizados fora do escopo de proteção do elemento <Suspense>. Verifique se as rotas internas mapeadas estão devidamente encapsuladas pelo elemento <Suspense fallback={...}> no arquivo src/App.tsx.
O TypeScript reclama que não pode resolver importações relativas de views ou componentes O caminho relativo fornecido para a chamada do import dinâmico na configuração do roteador possui erros de sintaxe ou letras. Lembre-se de que caminhos relativos dependem da localização exata do arquivo. No src/App.tsx, uma pasta admin deve ser acessada via ./views/admin/... respeitando as maiúsculas e minúsculas física das pastas.

🏁 Conclusão

Com a estrutura de rotas dinâmicas do React inicializada e as tipagens mapeadas com sucesso, temos a base para criar o motor de comunicação assíncrona.

No Módulo 07, criaremos o Contexto de Autenticação Reativa (AuthContext), programaremos os Interceptadores do Axios para anexar automaticamente o cabeçalho de token de forma transparente e projetaremos um Design System Responsivo de alta fidelidade utilizando os conceitos estéticos modernos de glassmorphism em CSS puro.


Voltar para o Sumário