--- name: react-patterns description: Modern React patterns and best practices. Implements hooks, context, composition, and performance optimization patterns. Use when user mentions "react patterns", "hooks", "react best practices", "component design", "react optimization". author: Descomplicar® Crescimento Digital version: 2.0.0 quality_score: 80 user_invocable: true desk_task: 1478 --- # React Patterns Skill para desenvolvimento React seguindo padrões modernos (React 18+/19). > **Regra #48:** Projectos React (incluindo Next.js) devem ser desenvolvidos no **container dev** (`server:"dev"`, path `/root/Dev/`). Sincroniza automaticamente com o PC local via Syncthing. ## Quando Usar - Desenvolver componentes React - Implementar state management - Optimizar performance (memoization, lazy loading) - Migrar de class components para hooks - Usar Server Components (Next.js App Router) ## Regras Core ### Hooks Fundamentais ```jsx // ✅ useState - estado simples const [count, setCount] = useState(0) const [user, setUser] = useState(null) // ✅ useEffect - side effects useEffect(() => { fetchData() return () => cleanup() // cleanup function }, [dependency]) // array dependências // ✅ useCallback - memoizar funções const handleClick = useCallback(() => { doSomething(id) }, [id]) // ✅ useMemo - memoizar valores computados const expensiveValue = useMemo(() => { return computeExpensive(data) }, [data]) // ✅ useRef - referências mutáveis const inputRef = useRef(null) ``` ### Component Patterns ```jsx // ✅ CORRECTO: Functional components function UserCard({ user, onSelect }: Props) { return (
onSelect(user.id)}> {user.name}
) } // ✅ CORRECTO: Composition over props drilling function Layout({ children }) { return
{children}
} // ❌ ERRADO: Class components (legacy) class UserCard extends React.Component { ... } ``` ### State Management ```jsx // ✅ Local state: useState // Para estado de um componente // ✅ Shared state: Context + useReducer const AppContext = createContext(null) function AppProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState) return ( {children} ) } // ✅ Server state: React Query / SWR const { data, isLoading } = useQuery({ queryKey: ['users'], queryFn: fetchUsers, }) // ❌ ERRADO: Redux para tudo // ❌ ERRADO: Estado global para estado local ``` ### Server Components (Next.js 13+) ```jsx // ✅ Server Component (default) - async, data fetching async function UserList() { const users = await db.users.findMany() // Direct DB access return
    {users.map(u =>
  • {u.name}
  • )}
} // ✅ Client Component - interactividade 'use client' function Counter() { const [count, setCount] = useState(0) return } // ✅ Padrão: Server parent + Client children // page.tsx (Server) → InteractiveSection.tsx ('use client') ``` ### Performance ```jsx // ✅ Lazy loading componentes const HeavyComponent = lazy(() => import('./HeavyComponent')) }> // ✅ React.memo para componentes puros const MemoizedCard = memo(function Card({ data }) { return
{data.title}
}) // ✅ Virtualização para listas grandes import { useVirtualizer } from '@tanstack/react-virtual' ``` ## Anti-Patterns | Anti-Pattern | Problema | Solução | |--------------|----------|---------| | useEffect para tudo | Complexidade | Server Components / React Query | | Props drilling | Manutenção | Context ou Composition | | Inline functions em JSX | Re-renders | useCallback | | State em URL | Perda estado | URL state com hooks | | Class components | Legacy | Functional + Hooks | | Index como key | Bugs listas | ID único | ## Checklist Componente - [ ] Functional component (não class) - [ ] TypeScript types/interfaces - [ ] Props destructuring com defaults - [ ] Hooks no topo (não condicionais) - [ ] Keys únicos em listas - [ ] Error boundaries para erros - [ ] Loading states considerados ## Estrutura Ficheiros ``` components/ ├── ui/ # Componentes base (Button, Input, Card) ├── features/ # Componentes feature-specific ├── layouts/ # Layout components └── providers/ # Context providers hooks/ ├── useAuth.ts ├── useLocalStorage.ts └── useDebounce.ts ``` ## Custom Hooks Úteis ### useDebounce ```tsx function useDebounce(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const timer = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(timer); }, [value, delay]); return debouncedValue; } // Uso const searchTerm = useDebounce(input, 500); ``` ### useLocalStorage ```tsx function useLocalStorage(key: string, initialValue: T) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch { return initialValue; } }); const setValue = (value: T | ((val: T) => T)) => { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); }; return [storedValue, setValue] as const; } ``` ### useFetch ```tsx function useFetch(url: string) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then(res => res.json()) .then(setData) .catch(setError) .finally(() => setLoading(false)); }, [url]); return { data, loading, error }; } ``` ## Padrões Avançados ### Compound Components ```tsx // Tab.tsx const TabsContext = createContext<{ activeTab: string; setActiveTab: (id: string) => void; } | null>(null); function Tabs({ children, defaultTab }: Props) { const [activeTab, setActiveTab] = useState(defaultTab); return ( {children} ); } Tabs.List = function TabList({ children }: Props) { return
{children}
; }; Tabs.Tab = function Tab({ id, children }: Props) { const { activeTab, setActiveTab } = useContext(TabsContext)!; return ( ); }; Tabs.Panel = function TabPanel({ id, children }: Props) { const { activeTab } = useContext(TabsContext)!; return activeTab === id ?
{children}
: null; }; // Uso Home Profile Home content Profile content ``` ### Render Props (legacy, preferir hooks) ```tsx // Evitar - usar custom hook } /> // Preferir const { data } = useFetch('/api/users'); return ; ``` ## Composition Patterns (Vercel Engineering) Padrões de composição para componentes React escaláveis. Fonte: Vercel composition-patterns. ### Regra #1: Evitar Boolean Props (CRITICAL) ```tsx // ❌ ERRADO: Booleans duplicam estados possíveis // ✅ CORRECTO: Variantes explícitas ``` Cada boolean duplica os estados possíveis. 5 booleans = 32 combinações, maioria impossível. ### Regra #2: Compound Components com Context (HIGH) ```tsx // ✅ Compound Components: context partilhado, composição explícita const ComposerContext = createContext(null) function ComposerFrame({ children }: { children: React.ReactNode }) { return
{children}
} function ComposerInput() { const { state, actions: { update }, meta } = use(ComposerContext) return ( update(s => ({ ...s, input: text }))} /> ) } // Exportar como compound const Composer = { Frame: ComposerFrame, Input: ComposerInput, Submit: ComposerSubmit, Footer: ComposerFooter, } // Uso: composição clara do que cada variante renderiza ``` ### Regra #3: State em Providers (HIGH) ```tsx // ❌ ERRADO: Estado preso dentro do componente function ForwardComposer() { const [state, setState] = useState(initialState) return ... } // Como ForwardButton acede ao state? useEffect sync? Refs? Prop drilling? // ✅ CORRECTO: State lifted para Provider function ForwardProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState(initialState) const submit = useForwardMessage() const inputRef = useRef(null) return ( {children} ) } // Agora QUALQUER componente dentro do Provider acede ao state function ForwardDialog() { return ( {/* acede state via context */} {/* acede submit via context */} ) } // Botão FORA do Composer.Frame mas DENTRO do Provider function ForwardButton() { const { actions } = use(ComposerContext) return } ``` **Princípio chave:** O boundary do Provider é o que importa, não o nesting visual. ### Regra #4: Interface Genérica para Dependency Injection (HIGH) ```tsx // ✅ Definir interface genérica: state + actions + meta interface ComposerContextValue { state: { input: string; attachments: Attachment[]; isSubmitting: boolean } actions: { update: (fn: (s: State) => State) => void; submit: () => void } meta: { inputRef: React.RefObject } } // ✅ Múltiplos providers implementam a MESMA interface function ChannelProvider({ channelId, children }) { const { state, update, submit } = useGlobalChannel(channelId) return {children} } function ForwardProvider({ children }) { const [state, setState] = useState(initialState) return {children} } // O mesmo Composer.Input funciona com AMBOS os providers! ``` **Princípio:** UI = pedaços reutilizáveis compostos. State = injectado pelo provider. Trocar provider, manter UI. ### Regra #5: Children > Render Props (MEDIUM) ```tsx // ❌ Render props (inflexível, difícil de ler)
} renderFooter={() => <>} /> // ✅ Children (composição natural)
// Excepção: render props quando parent passa dados } /> ``` ### Regra #6: React 19 APIs (MEDIUM) ```tsx // ✅ React 19: ref como prop normal (sem forwardRef) function Input({ ref, ...props }: Props & { ref?: React.Ref }) { return } // ✅ React 19: use() em vez de useContext() const value = use(MyContext) // pode ser chamado condicionalmente! ``` ### Checklist Composição - [ ] Zero boolean props para variantes (usar componentes explícitos) - [ ] Compound components com context partilhado - [ ] State em Provider (não dentro do componente UI) - [ ] Interface genérica (state/actions/meta) - [ ] Children para composição, render props só para data passthrough - [ ] React 19: `use()` e ref como prop --- ## Datasets Dify (Consulta Obrigatória) Em caso de dúvidas ou para aprofundar conhecimento, consultar os seguintes datasets via MCP: | Dataset | ID | Prioridade | |---------|----|-----------:| | **TI (Tecnologia da Informação)** | `7f63ec0c-6321-488c-b107-980140199850` | 1 | | **Desenvolvimento de Software** | `e7c7decc-0ded-4351-ab14-b110b3c38ec9` | 1 | | **Desenvolvimento de WebSites** | `c8489151-de94-42b2-8cee-c0b961cfac6d` | 2 | | **UX e Usabilidade** | `e14ab89e-8910-43b6-becf-d57c78afd62d` | 3 | ### Como Consultar ```javascript // Pesquisar padrões React mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments({ dataset_id: "e7c7decc-0ded-4351-ab14-b110b3c38ec9", query: "react hooks state management" }) // Server Components Next.js mcp__dify-kb__dify_kb_retrieve_segments({ dataset_id: "7f63ec0c-6321-488c-b107-980140199850", query: "nextjs server components app router" }) // UX e performance mcp__dify-kb__dify_kb_retrieve_segments({ dataset_id: "e14ab89e-8910-43b6-becf-d57c78afd62d", query: "performance loading states" }) ``` ### Quando Consultar - Implementar hooks customizados - Escolher state management - Optimizar performance (memoization, lazy loading) - Server Components vs Client Components - Padrões de UX em React --- **Versão**: 1.0.0 | **Autor**: Descomplicar® --- ## Quando NÃO Usar - Para tarefas fora do domínio de especialização desta skill - Quando outra skill mais específica está disponível - Para operações que requerem aprovação manual obrigatória - Quando os requisitos não estão claramente definidos ## Protocolo de Execução 1. **Análise Inicial** - Verificar requisitos e contexto - Identificar ferramentas necessárias 2. **Preparação** - Validar acesso a recursos - Preparar ambiente de trabalho 3. **Execução** - Executar operações de forma incremental - Validar cada passo antes de prosseguir 4. **Validação** - Verificar resultados obtidos - Confirmar sucesso da operação 5. **Conclusão** - Documentar alterações realizadas - Reportar status final e próximos passos ## Exemplos de Uso ### Exemplo 1: Caso Básico ``` User: [requisição simples relacionada com react-patterns] Skill: [execução directa com validação] Output: [resultado conciso e accionável] ``` ### Exemplo 2: Caso Complexo ``` User: [requisição multi-passo ou complexa] Skill: 1. Análise dos requisitos 2. Planeamento da abordagem 3. Execução faseada 4. Validação contínua Output: [resultado detalhado com próximos passos] ``` ### Exemplo 3: Caso com Dependências ``` User: [requisição que depende de outros sistemas] Skill: 1. Verificar dependências disponíveis 2. Coordenar com skills/MCPs necessários 3. Executar workflow integrado Output: [resultado completo com referências] ```