Skill v1.0.1
currentLLM-judged scan95/1003 files
version: "1.0.1" name: react-components-patterns scope: domain target: organizador-base-conhecimento description: | Comprehensive guide to React component patterns used in the Plataforma B2B de treinamento técnico corporativo educational platform. This skill covers functional components with hooks, composition patterns, state management, props flow, and error handling strategies essential for building maintainable React applications.
Learn how to create reusable, testable components following React best practices while avoiding common antipatterns like prop drilling, unnecessary class components, and improper state management. The skill emphasizes composition over inheritance, unidirectional data flow, and separation of concerns.
Real-world examples are taken directly from the project codebase, including CLearningSystem, BashLearningSystem, Breadcrumb, AreaCard, and FlashcardModal components. Each pattern is demonstrated with production code showing how architectural decisions were implemented in a 5,500+ line React application with 17 components.
Key topics include functional components (vs class components), React Hooks (useState, useEffect, custom hooks), component composition strategies, props vs Context API decision-making, controlled components for forms, error boundaries for resilience, and testing patterns with Vitest and Testing Library.
This skill is essential for understanding the system's component architecture, contributing new features, refactoring duplicated code (current 25% duplication target: <10%), and maintaining consistency across the 227-module educational platform. Includes troubleshooting guides for common React issues encountered during development.
keywords: | react, components, hooks, useState, useEffect, functional-components, composition, props, context-api, error-boundary, patterns, jsx, react-patterns, component-architecture, reusable-components
allowed-tools: | Read, Write, Edit, Grep, Glob, Bash
React Components Patterns
Padrões de Componentes React para Plataforma B2B de treinamento técnico corporativoVersão: 1.0.0Última Atualização: 2025-11-16Target: React 18.3.1 + HooksProjeto: Plataforma B2B de treinamento técnico corporativo
📋 Índice
- Overview
- Quando Usar Esta Skill
- Conceitos Fundamentais
- Padrões de Componentes
- Exemplos Práticos do Projeto
- Antipadrões a Evitar
- Troubleshooting
- Referências
🎯 Overview
Esta skill documenta todos os padrões de componentes React utilizados no Plataforma B2B de treinamento técnico corporativo, um sistema educacional com 17 componentes React, 227 módulos educacionais e 5 sistemas integrados de aprendizado.
O que você vai aprender:
- Como criar componentes funcionais reutilizáveis e testáveis
- Quando usar hooks vs. Context API vs. props drilling
- Padrões de composição (composition over inheritance)
- Estratégias de state management local
- Error boundaries e tratamento de erros
- Testes de componentes com Vitest e Testing Library
Por que esta skill é importante:
- ✅ Consistência: Garante que novos componentes seguem os mesmos padrões existentes
- ✅ Manutenibilidade: Reduz duplicação de código (meta: 25% → <10%)
- ✅ Testabilidade: Componentes funcionais são mais fáceis de testar
- ✅ Performance: Hooks permitem otimizações (useMemo, useCallback)
- ✅ Escalabilidade: Composição permite crescimento sustentável
📋 Quando Usar Esta Skill
Cenário 1: Criando Novo Componente
Situação: Você precisa adicionar um novo componente (ex: LessonCard, ProgressBar, QuizModal)
Use esta skill para:
- Decidir entre functional component vs. class component (sempre functional!)
- Escolher hooks apropriados (useState, useEffect, custom hooks)
- Definir interface de props (destructuring, PropTypes/TypeScript)
- Estruturar JSX de forma legível e manutenível
Exemplo de aplicação:
// ✅ Seguindo padrões da skillfunction LessonCard({ title, duration, completed, onComplete, onClick }) {const [isExpanded, setIsExpanded] = useState(false);return (<divonClick={onClick}className="card"><h3>{title}</h3><span>{duration}</span>{completed && <span>✅</span>}</div>);}
Cenário 2: Refatorando Código Duplicado
Situação: Você identificou 5 componentes com lógica similar (ex: CLearningSystem, BashLearningSystem, RustLearningSystem)
Use esta skill para:
- Extrair lógica comum em hooks customizados
- Criar componentes genéricos (BaseLearningSystem)
- Aplicar composition patterns
- Reduzir de 800+ linhas duplicadas para componente reutilizável
Exemplo de refatoração:
// ❌ Antes: 5 componentes com 800 linhas duplicadasfunction CLearningSystem() {const [notes, setNotes] = useState('');const [progress, setProgress] = useState([]);// ... 160 linhas de lógica duplicada}// ✅ Depois: Hook customizado + componente genéricofunction useCourseLogic(courseId) {const [notes, setNotes, saveStatus] = useAutoSaveNotes(courseId);const [progress, updateProgress] = useModuleProgress(courseId);return { notes, setNotes, saveStatus, progress, updateProgress };}function BaseLearningSystem({ courseId, courseData }) {const { notes, setNotes, progress, updateProgress } = useCourseLogic(courseId);// ... 40 linhas de lógica genérica}
Impacto: Reduz manutenção de 5 arquivos para 1 componente + 2 hooks
Cenário 3: Debugging Problemas de Estado
Situação: Componente re-renderiza infinitamente ou estado não atualiza corretamente
Use esta skill para:
- Entender fluxo unidirecional de dados (props down, events up)
- Diagnosticar problemas com useEffect dependencies
- Identificar mutações acidentais de estado
- Aplicar padrões de imutabilidade
Exemplo de debug:
// ❌ Problema: Re-render infinitouseEffect(() => {setData(fetchData()); // ⚠️ Sem array de dependências!});// ✅ Solução: Dependências corretasuseEffect(() => {async function load() {const result = await fetchData();setData(result);}load();}, []); // ✅ Roda apenas uma vez
💡 Conceitos Fundamentais
1. Functional Components com Hooks
Princípio: Sempre use functional components em vez de class components.
Por quê:
- ✅ Menos código boilerplate (sem constructor, bind)
- ✅ Hooks permitem reutilizar lógica (custom hooks)
- ✅ Mais fácil de testar (funções puras)
- ✅ Melhor suporte a TypeScript
- ✅ React team recomenda (class components legacy)
Anatomia de um functional component:
import React, { useState, useEffect } from 'react';/*** Card de área de estudo do Hub** Props:* - titulo: string - Nome da área (ex: "Bash Shell Scripting")* - descricao: string - Descrição curta* - icone: string - Emoji representativo* - horas: number - Duração total em horas* - modulos: number - Quantidade de aulas* - onClick: function - Callback ao clicar*/function AreaCard({ titulo, descricao, icone, horas, modulos, onClick }) {// Estado local (se necessário)const [isHovered, setIsHovered] = useState(false);// Efeitos colaterais (se necessário)useEffect(() => {// Lógica que roda após renderconsole.log(`AreaCard ${titulo} montado`);}, [titulo]); // Dependências// Event handlersconst handleMouseEnter = () => setIsHovered(true);const handleMouseLeave = () => setIsHovered(false);// JSX Renderreturn (<divonClick={onClick}onMouseEnter={handleMouseEnter}onMouseLeave={handleMouseLeave}className={`card ${isHovered ? 'card-hover' : ''}`}><div className="card-header"><span className="icon">{icone}</span><h3>{titulo}</h3></div><p className="description">{descricao}</p><div className="meta"><span>�� {modulos} aulas</span><span>⏱️ {horas}h</span></div></div>);}export default AreaCard;
Checklist de qualidade:
- [ ] Usa function (não arrow function para componentes principais)
- [ ] Props destructured na assinatura
- [ ] Comentário JSDoc descrevendo props
- [ ] Event handlers com nomes descritivos (handleClick, handleChange)
- [ ] Hooks no topo do componente (antes de qualquer condicional)
- [ ] JSX legível (indentação correta, componentes pequenos)
- [ ] export default ao final
2. Composition Over Inheritance
Princípio: Componha componentes de partes menores, não herde de classes base.
Por quê:
- ✅ Mais flexível (mix and match)
- ✅ Menos acoplamento
- ✅ Reutilização via props e children
- ✅ Alinhado com filosofia React
Exemplo Real: Breadcrumb Component
// ✅ Composition: Breadcrumb é composto de itens menoresfunction Breadcrumb({ items }) {return (<nav aria-label="Breadcrumb" className="breadcrumb">{items.map((item, index) => (<React.Fragment key={index}><BreadcrumbItem {...item} />{index < items.length - 1 && <BreadcrumbSeparator />}</React.Fragment>))}</nav>);}// Componente pequeno e reutilizávelfunction BreadcrumbItem({ label, icon, onClick, current }) {return (<buttononClick={onClick}aria-current={current ? 'page' : undefined}className={`breadcrumb-item ${current ? 'current' : ''}`}>{icon && <span aria-hidden="true">{icon}</span>}{label}</button>);}// Separador visualfunction BreadcrumbSeparator() {return <span aria-hidden="true" className="separator">›</span>;}// Uso no CLearningSystem<Breadcrumb items={[{ label: 'Hub', icon: '🏠', onClick: () => setView('hub') },{ label: 'Curso de C', icon: '📖', onClick: () => setView('course') },{ label: 'Aula 1.1', icon: '📝', current: true }]} />
Benefícios aplicados:
- Breadcrumb testável independentemente
- BreadcrumbItem reutilizável em outros contextos
- Fácil adicionar novos tipos (BreadcrumbCollapse para mobile)
Arquivo real: src/components/Breadcrumb.jsx:15-45
3. Props vs. Context API
Decisão: Quando usar props drilling vs. Context API?
Use Props quando:
- ✅ Componente pai e filho próximos (1-2 níveis)
- ✅ Dados específicos de um componente
- ✅ Performance é crítica (props são mais rápidos)
- ✅ Relação clara parent → child
Use Context API quando:
- ✅ Dados globais (tema, usuário, idioma)
- ✅ Props drilling profundo (3+ níveis)
- ✅ Muitos componentes precisam do mesmo dado
- ✅ Evitar "prop tunneling"
Exemplo Props (Caso Comum no Projeto):
// ✅ Props drilling aceitável (apenas 2 níveis)function CLearningSystem() {const [selectedLesson, setSelectedLesson] = useState(null);return (<LessonListlessons={courseData.lessons}selectedId={selectedLesson?.id}onSelect={setSelectedLesson}/>);}function LessonList({ lessons, selectedId, onSelect }) {return lessons.map(lesson => (<LessonItemkey={lesson.id}lesson={lesson}isSelected={lesson.id === selectedId}onClick={() => onSelect(lesson)}/>));}
Exemplo Context (Planejado para Release 2.0):
// Context para tema (usado em 10+ componentes)const ThemeContext = React.createContext('light');function App() {const [theme, setTheme] = useState('light');return (<ThemeContext.Provider value={{ theme, setTheme }}><Header /><MainContent /><Footer /></ThemeContext.Provider>);}// Qualquer componente profundo pode acessarfunction ThemeToggle() {const { theme, setTheme } = useContext(ThemeContext);return (<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>{theme === 'light' ? '🌙' : '☀️'}</button>);}
Regra prática: Start with props, migrate to Context when passing through 3+ components.
4. Controlled vs. Uncontrolled Components
Controlled: React controla o estado do input (recomendado)
Uncontrolled: DOM controla o estado (usar apenas se necessário)
Exemplo Controlled (Caderno de Notas):
function NotesView({ courseId }) {const [notes, setNotes, saveStatus] = useAutoSaveNotes(courseId);return (<textareavalue={notes} // ✅ Controlled: React é source of truthonChange={(e) => setNotes(e.target.value)}placeholder="Suas anotações..."/>);}
Arquivo real: src/components/CNotesView.jsx:45-60
Por que controlled:
- ✅ Estado sempre sincronizado
- ✅ Fácil validar e formatar input
- ✅ Auto-save funciona out of the box
- ✅ Testável (pode setar valor programaticamente)
5. Error Boundaries
Princípio: Componentes não devem crashar a aplicação inteira.
Implementação:
// ErrorBoundary.jsxclass ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false, error: null };}static getDerivedStateFromError(error) {return { hasError: true, error };}componentDidCatch(error, errorInfo) {console.error('Error caught by boundary:', error, errorInfo);// Futuramente: enviar para Sentry}render() {if (this.state.hasError) {return (<div className="error-boundary"><h2>⚠️ Algo deu errado</h2><p>{this.state.error?.message}</p><button onClick={() => window.location.reload()}>Recarregar Página</button></div>);}return this.props.children;}}// Uso no SistemaEducacionalCompletofunction App() {return (<ErrorBoundary><HubView /></ErrorBoundary>);}
Arquivo real: src/components/ErrorBoundary.jsx:1-40
Nota: Error boundaries devem ser class components (única exceção à regra functional-first)
🏗️ Padrões de Componentes
Padrão 1: Presentational vs. Container
Presentational (Dumb): Apenas UI, recebe tudo via props
// ✅ Presentational: apenas renderizafunction AreaCard({ titulo, icone, onClick }) {return (<div onClick={onClick} className="card"><span>{icone}</span><h3>{titulo}</h3></div>);}
Container (Smart): Gerencia estado e lógica
// ✅ Container: gerencia dados e lógicafunction HubView() {const [areas, setAreas] = useState(studyAreas);const [filter, setFilter] = useState('');const filteredAreas = areas.filter(a =>a.titulo.toLowerCase().includes(filter.toLowerCase()));return (<div><inputvalue={filter}onChange={(e) => setFilter(e.target.value)}placeholder="Buscar área..."/>{filteredAreas.map(area => (<AreaCard key={area.id} {...area} onClick={() => navigate(area.id)} />))}</div>);}
Arquivo real: src/components/HubView.jsx:30-80
Benefício: Presentational components são mais testáveis e reutilizáveis
Padrão 2: Render Props (Avançado)
Uso: Compartilhar lógica entre componentes via função render
// Componente que gerencia mouse positionfunction MouseTracker({ render }) {const [position, setPosition] = useState({ x: 0, y: 0 });useEffect(() => {const handleMove = (e) => setPosition({ x: e.clientX, y: e.clientY });window.addEventListener('mousemove', handleMove);return () => window.removeEventListener('mousemove', handleMove);}, []);return render(position);}// Uso<MouseTracker render={({ x, y }) => (<p>Mouse em: {x}, {y}</p>)} />
Nota: Padrão avançado, não usado atualmente no projeto (hooks são preferidos)
Padrão 3: Higher-Order Components (HOC)
Definição: Função que recebe componente e retorna novo componente
// HOC para adicionar loading statefunction withLoading(Component) {return function WithLoadingComponent({ isLoading, ...props }) {if (isLoading) {return <div className="spinner">Carregando...</div>;}return <Component {...props} />;};}// Usoconst LessonListWithLoading = withLoading(LessonList);<LessonListWithLoadingisLoading={loading}lessons={lessons}/>
Nota: HOCs são legado, hooks customizados são preferidos
🔧 Exemplos Práticos do Projeto
Exemplo 1: AreaCard (Componente Mais Simples)
Localização: src/components/AreaCard.jsx
Responsabilidade: Card clicável de área de estudo no Hub
Código completo:
function AreaCard({titulo,descricao,icone,horas,modulos,onClick}) {return (<divonClick={onClick}className="bg-white rounded-lg p-6 shadow-lghover:shadow-xl transition-shadow cursor-pointerborder border-gray-200"><div className="flex items-center gap-3 mb-3"><span className="text-4xl">{icone}</span><h3 className="text-xl font-bold text-gray-800">{titulo}</h3></div><p className="text-gray-600 mb-4 line-clamp-2">{descricao}</p><div className="flex gap-4 text-sm text-gray-500"><span>�� {modulos} aulas</span><span>⏱️ {horas}h</span></div></div>);}export default AreaCard;
Análise do padrão:
- ✅ Functional component puro (sem estado)
- ✅ Props destructured
- ✅ Tailwind classes inline
- ✅ Acessibilidade implícita (div clicável com onClick)
- ✅ Feedback visual (hover, transition)
Uso no HubView:
<AreaCardtitulo="Bash Shell Scripting"descricao="Domine o terminal"icone="💻"horas={16}modulos={16}onClick={() => setCurrentView('bash')}/>
Arquivo real: src/components/AreaCard.jsx:1-35
Exemplo 2: Breadcrumb (Componente com Estado e Acessibilidade)
Localização: src/components/Breadcrumb.jsx
Responsabilidade: Navegação hierárquica (Hub > Curso > Aula)
Features:
- ✅ WCAG 2.1 AA compliant
- ✅ Responsivo (colapsa em mobile)
- ✅ Sticky (sempre visível)
- ✅ Clicável (navegação entre níveis)
Código (simplificado):
function Breadcrumb({ items }) {return (<navaria-label="Breadcrumb"className="sticky top-0 z-10 bg-white shadow-md px-6 py-3"><ol className="flex items-center gap-2">{items.map((item, index) => (<React.Fragment key={index}><li><buttononClick={item.onClick}aria-current={item.current ? 'page' : undefined}className={`flex items-center gap-2 px-3 py-1 rounded${item.current? 'bg-blue-100 text-blue-700 font-semibold': 'hover:bg-gray-100 text-gray-600'}`}>{item.icon && <span aria-hidden="true">{item.icon}</span>}{item.label}</button></li>{index < items.length - 1 && (<li aria-hidden="true" className="text-gray-400">›</li>)}</React.Fragment>))}</ol></nav>);}
Arquivo real: src/components/Breadcrumb.jsx:1-95
Padrões aplicados:
- ✅ Composition (Breadcrumb + BreadcrumbItem)
- ✅ Acessibilidade (aria-label, aria-current, semantic HTML)
- ✅ Responsividade (classes Tailwind)
- ✅ State management via props (items array)
Validação US-061: 13/13 critérios de aceite completos ✅
Exemplo 3: CLearningSystem (Componente Complexo com Estado)
Localização: src/components/CLearningSystem.jsx
Responsabilidade: Sistema completo de aprendizado do Curso de C
Estado gerenciado:
currentView: 'course' | 'lesson' | 'notes'selectedLesson: Lesson | nullcompletedLessons: string[]showFlashcards: boolean
Estrutura (simplificada):
function CLearningSystem({ onBack }) {// Estado de navegaçãoconst [currentView, setCurrentView] = useState('course');const [selectedLesson, setSelectedLesson] = useState(null);// Estado de progressoconst [completedLessons, setCompletedLessons] = useState([]);// Estado de modalsconst [showFlashcards, setShowFlashcards] = useState(false);// Carregar progresso do localStorage ao montaruseEffect(() => {const saved = localStorage.getItem('plataforma-b2b_progress_c');if (saved) {const { completedLessons } = JSON.parse(saved);setCompletedLessons(completedLessons);}}, []);// Handler de conclusão de aulaconst handleCompleteLesson = (lessonId) => {if (completedLessons.includes(lessonId)) return;const newCompleted = [...completedLessons, lessonId];setCompletedLessons(newCompleted);localStorage.setItem('plataforma-b2b_progress_c', JSON.stringify({completedLessons: newCompleted,lastUpdated: Date.now()}));};// Render condicional baseado em currentViewif (currentView === 'notes') {return <CNotesView onBack={() => setCurrentView('course')} />;}if (currentView === 'lesson' && selectedLesson) {return (<div><Breadcrumb items={[{ label: 'Hub', icon: '🏠', onClick: onBack },{ label: 'Curso de C', icon: '📖', onClick: () => setCurrentView('course') },{ label: selectedLesson.title, icon: '📝', current: true }]} /><LessonContent lesson={selectedLesson} /><button onClick={() => handleCompleteLesson(selectedLesson.id)}>✅ Marcar como Concluída</button></div>);}// View padrão: lista de aulasreturn (<div><Breadcrumb items={[{ label: 'Hub', icon: '🏠', onClick: onBack },{ label: 'Curso de C', icon: '📖', current: true }]} /><button onClick={() => setCurrentView('notes')}>�� Estudar</button><button onClick={() => setShowFlashcards(true)}>�� Flash Cards</button>{cCourseData.sections.map(section => (<Section key={section.sectionTitle}><h2>{section.sectionTitle}</h2>{section.modules.map(lesson => (<LessonItemkey={lesson.id}lesson={lesson}completed={completedLessons.includes(lesson.id)}onClick={() => {setSelectedLesson(lesson);setCurrentView('lesson');}}/>))}</Section>))}{showFlashcards && (<FlashcardModalcards={cCourseData.flashcards}onClose={() => setShowFlashcards(false)}/>)}</div>);}
Arquivo real: src/components/CLearningSystem.jsx:1-450
Padrões aplicados:
- ✅ Multiple useState hooks (separação de concerns)
- ✅ useEffect para side effects (localStorage)
- ✅ Controlled components (estado sempre sincronizado)
- ✅ Conditional rendering (view switching)
- ✅ Event handlers descritivos
- ✅ Props drilling (onBack callback)
Oportunidade de refatoração (US-043):
- Extrair
useAutoSaveNoteshook - Extrair
useModuleProgresshook - Criar
BaseLearningSystemcomponente genérico - Reduzir 800 linhas duplicadas nos 5 sistemas
❌ Antipadrões a Evitar
1. Class Components (Exceto Error Boundaries)
❌ Não fazer:
class AreaCard extends React.Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this); // ⚠️ Boilerplate}handleClick() {this.props.onClick();}render() {return <div onClick={this.handleClick}>{this.props.titulo}</div>;}}
✅ Fazer:
function AreaCard({ titulo, onClick }) {return <div onClick={onClick}>{titulo}</div>;}
Por quê: Functional components são mais simples, testáveis e alinhados com React moderno.
2. Mutação Direta de Estado
❌ Não fazer:
const [lessons, setLessons] = useState([]);// ⚠️ Mutação diretalessons.push(newLesson);setLessons(lessons); // React pode não detectar mudança!
✅ Fazer:
// ✅ ImutabilidadesetLessons([...lessons, newLesson]);// ousetLessons(prev => [...prev, newLesson]);
Por quê: React depende de referências para detectar mudanças. Mutação direta quebra isso.
3. useEffect sem Array de Dependências
❌ Não fazer:
useEffect(() => {fetchData(); // ⚠️ Roda em todo render!});
✅ Fazer:
useEffect(() => {fetchData();}, []); // ✅ Roda apenas uma vez (mount)// Ou com dependênciasuseEffect(() => {fetchData(courseId);}, [courseId]); // ✅ Roda quando courseId muda
Por quê: Sem array de dependências, effect roda em todo render (performance ruim).
4. Props Drilling Excessivo
❌ Não fazer:
// 5 níveis de props drilling!<App user={user}><Layout user={user}><Sidebar user={user}><Menu user={user}><UserInfo user={user} /></Menu></Sidebar></Layout></App>
✅ Fazer:
// Context API para dados globaisconst UserContext = createContext();<UserContext.Provider value={user}><App><Layout><Sidebar><Menu><UserInfo /> {/* acessa via useContext */}</Menu></Sidebar></Layout></App></UserContext.Provider>
Por quê: Props drilling profundo é difícil de manter. Context é melhor para dados globais.
5. Inline Functions em Props (Performance)
❌ Evitar em listas grandes:
{lessons.map(lesson => (<LessonItemkey={lesson.id}onClick={() => handleClick(lesson.id)} // ⚠️ Nova função a cada render/>))}
✅ Fazer (se performance crítica):
const handleLessonClick = useCallback((lessonId) => {// lógica}, []);{lessons.map(lesson => (<LessonItemkey={lesson.id}onClick={handleLessonClick}lessonId={lesson.id}/>))}
Por quê: Inline functions criam nova referência a cada render, podem causar re-renders desnecessários.
Nota: No projeto atual (227 módulos), performance ainda OK. Otimizar quando necessário.
🚨 Troubleshooting
Problema 1: "Cannot read property 'map' of undefined"
Sintoma:
Uncaught TypeError: Cannot read property 'map' of undefinedat CLearningSystem.jsx:45
Causa: Array de dados ainda não carregado quando componente tenta renderizar.
Solução:
// ❌ Errofunction LessonList({ lessons }) {return lessons.map(lesson => <LessonItem {...lesson} />);}// ✅ Solução: Early return ou default valuefunction LessonList({ lessons = [] }) {if (!lessons || lessons.length === 0) {return <p>Nenhuma aula disponível</p>;}return lessons.map(lesson => <LessonItem {...lesson} />);}
Arquivo: Problema comum em CLearningSystem.jsx:90, BashLearningSystem.jsx:85
Problema 2: "Warning: Each child in a list should have a unique key prop"
Sintoma:
Warning: Each child in a list should have a unique "key" prop.
Causa: Esqueceu de adicionar prop key ao mapear array.
Solução:
// ❌ Erro{lessons.map(lesson => (<LessonItem title={lesson.title} />))}// ✅ Solução: Usar ID único{lessons.map(lesson => (<LessonItem key={lesson.id} title={lesson.title} />))}// ⚠️ Evitar usar index (exceto se lista estática){lessons.map((lesson, index) => (<LessonItem key={index} {...lesson} /> // OK apenas se lista não muda))}
Problema 3: "Maximum update depth exceeded"
Sintoma:
Error: Maximum update depth exceeded. This can happen when a componentrepeatedly calls setState inside componentWillUpdate or componentDidUpdate.
Causa: useEffect sem dependências corretas causando loop infinito.
Solução:
// ❌ Loop infinitouseEffect(() => {setData(data + 1); // ⚠️ Atualiza data, que causa re-render, que roda effect novamente});// ✅ Solução 1: Array de dependências vaziouseEffect(() => {setData(1);}, []); // Roda apenas uma vez// ✅ Solução 2: Dependências corretasuseEffect(() => {if (shouldUpdate) {setData(newValue);}}, [shouldUpdate]); // Roda apenas quando shouldUpdate muda
Problema 4: Estado não atualiza imediatamente
Sintoma:
const [count, setCount] = useState(0);const handleClick = () => {setCount(count + 1);console.log(count); // ⚠️ Ainda mostra valor antigo!};
Causa: setState é assíncrono. Valor atualizado só disponível no próximo render.
Solução:
// ✅ Usar functional update se depende do valor anteriorconst handleClick = () => {setCount(prev => {console.log(prev); // Valor mais recentereturn prev + 1;});};// ✅ Ou usar useEffect para reagir a mudançasuseEffect(() => {console.log('Count atualizado:', count);}, [count]);
Problema 5: Component re-renderiza muitas vezes
Sintoma: Performance ruim, componente renderiza 10+ vezes por interação.
Diagnóstico: Usar React DevTools Profiler.
Causas comuns:
- Inline functions em props (criar nova função a cada render)
- Objetos/arrays criados inline em props
- Context que muda frequentemente
Soluções:
// ❌ Causa re-rendersfunction Parent() {return <Child config={{ foo: 'bar' }} />; // ⚠️ Novo objeto a cada render}// ✅ Solução: useMemo para valores computadosfunction Parent() {const config = useMemo(() => ({ foo: 'bar' }), []);return <Child config={config} />;}// ✅ Solução: React.memo para componentes purosconst Child = React.memo(function Child({ config }) {return <div>{config.foo}</div>;});
Arquivo útil: .claude/skills/vite-build-optimization/ para análise de bundle
📚 Referências
Skills Relacionadas
- [component-refactor](../component-refactor/SKILL.md) - Padrões de refatoração para reduzir duplicação
- [react-hooks-custom](../react-hooks-custom/SKILL.md) - Criação de hooks customizados
- [system-state-management](../system-state-management/SKILL.md) - State management avançado
- [testing-strategy-vitest](../testing-strategy-vitest/SKILL.md) - Testes de componentes React
Documentação Técnica
- [docs/tecnico/architecture/01-visao-geral-arquitetura.md](../../docs/tecnico/architecture/01-visao-geral-arquitetura.md) - Arquitetura completa (4 camadas)
- [docs/conceitual/01-visao-geral/00-definicoes-principais.md](../../docs/conceitual/01-visao-geral/00-definicoes-principais.md) - Glossário e nomenclatura
Código Real do Projeto
Componentes Exemplares:
src/components/AreaCard.jsx- Componente simples e purosrc/components/Breadcrumb.jsx- Acessibilidade e composiçãosrc/components/CLearningSystem.jsx- Componente complexo com estadosrc/components/ErrorBoundary.jsx- Error handling
Hooks Customizados (Planejados):
src/hooks/useAutoSaveNotes.js- Auto-save para notassrc/hooks/useModuleProgress.js- Progresso de aulas
Recursos Externos
- [React Docs - Components and Props](https://react.dev/learn/components-and-props)
- [React Docs - Hooks](https://react.dev/reference/react)
- [React Patterns](https://reactpatterns.com/) - Catálogo de padrões
- [Kent C. Dodds - Application State Management](https://kentcdodds.com/blog/application-state-management-with-react) - Props vs Context
📝 Arquivos Auxiliares
Esta skill possui 3 arquivos auxiliares detalhados:
- [functional-components.md](./auxiliary/functional-components.md) - Guia completo de functional components
- [hooks-guide.md](./auxiliary/hooks-guide.md) - useState, useEffect, custom hooks em profundidade
- [composition-patterns.md](./auxiliary/composition-patterns.md) - Padrões avançados de composição
📍 Você está em: .claude/skills/react-components-patterns/SKILL.md 📅 Criado em: 2025-11-16 👤 Mantido por: João Pelegrino + Claude Code 🎯 Uso: Referência para criar e manter componentes React no projeto 🔄 Última auditoria: 2025-11-16 📊 Auto-discovery score: TBD (testar após criação)