Especialização Frontend com React & TypeScript • Demonstrações Práticas Executáveis


🎯 Contexto e Objetivo Prático

Otimização de computação intensiva com useMemo e estabilização de referências de funções com useCallback para componentes memoizados.


💻 Código Fonte React 19 (TSX)

// ExpensiveListFilter.tsx
import React, { useState, useMemo, useCallback } from "react";

interface ProductRecord {
  id: string;
  sku: string;
  price: number;
  category: "hardware" | "software" | "cloud";
}

// Componente Filho Memoizado para evitar re-render inútil
const ProductRow = React.memo(function ProductRow({
  product,
  onSelect
}: {
  product: ProductRecord;
  onSelect: (sku: string) => void;
}) {
  return (
    <tr className="border-b hover:bg-slate-50">
      <td className="p-2 font-mono text-xs">{product.sku}</td>
      <td className="p-2 text-sm">{product.category}</td>
      <td className="p-2 text-sm font-semibold">R$ {product.price.toFixed(2)}</td>
      <td className="p-2">
        <button
          onClick={() => onSelect(product.sku)}
          className="text-xs bg-slate-100 hover:bg-slate-200 px-2 py-1 rounded"
        >
          Selecionar
        </button>
      </td>
    </tr>
  );
});

export function ProductCatalog({ initialProducts }: { initialProducts: ProductRecord[] }) {
  const [filterCategory, setFilterCategory] = useState<string>("all");
  const [selectedSku, setSelectedSku] = useState<string | null>(null);

  // 1. useMemo: Recalcula o filtro apenas se a categoria ou lista mudarem
  const filteredProducts = useMemo(() => {
    if (filterCategory === "all") return initialProducts;
    return initialProducts.filter(p => p.category === filterCategory);
  }, [initialProducts, filterCategory]);

  // 2. useCallback: Mantém a mesma referência de função para não invalidar o React.memo
  const handleSelectProduct = useCallback((sku: string) => {
    setSelectedSku(sku);
    console.log(`SKU selecionado: ${sku}`);
  }, []);

  return (
    <div className="p-4">
      <div className="mb-4 flex items-center gap-4">
        <select
          value={filterCategory}
          onChange={e => setFilterCategory(e.target.value)}
          className="border p-2 rounded text-sm"
        >
          <option value="all">Todas as Categorias</option>
          <option value="hardware">Hardware</option>
          <option value="cloud">Cloud</option>
        </select>
        <span className="text-sm text-slate-500">
          Exibindo {filteredProducts.length} de {initialProducts.length} registros
        </span>
      </div>

      <table className="w-full text-left border-collapse">
        <tbody>
          {filteredProducts.map(prod => (
            <ProductRow key={prod.id} product={prod} onSelect={handleSelectProduct} />
          ))}
        </tbody>
      </table>
    </div>
  );
}

🖥️ Saída de Renderização Visual e Comportamento

[Catálogo Otimizado]
Filtro: Cloud | Exibindo 2 de 5 registros
SKU: CLD-AWS-01  | Preço: R$ 450,00  [Selecionar]
SKU: CLD-GCP-02  | Preço: R$ 890,00  [Selecionar]