Files
claude-plugins/dev-tools/skills/react-patterns/SKILL.md
Emanuel Almeida 2cb3210962 feat: adiciona 12 plugins Descomplicar ao marketplace
Plugins: automacao, crm-ops, design-media, dev-tools, gestao,
infraestrutura, marketing, negocio, perfex-dev, project-manager,
wordpress + hello-plugin (existente).

Totais: 83 skills, 44 agents, 12 datasets.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 21:41:24 +00:00

15 KiB

name, description, author, version, quality_score, user_invocable, desk_task
name description author version quality_score user_invocable desk_task
react-patterns 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". Descomplicar® Crescimento Digital 2.0.0 80 true 1478

React Patterns

Skill para desenvolvimento React seguindo padrões modernos (React 18+/19).

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

// ✅ useState - estado simples
const [count, setCount] = useState(0)
const [user, setUser] = useState<User | null>(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<HTMLInputElement>(null)

Component Patterns

// ✅ CORRECTO: Functional components
function UserCard({ user, onSelect }: Props) {
  return (
    <div onClick={() => onSelect(user.id)}>
      {user.name}
    </div>
  )
}

// ✅ CORRECTO: Composition over props drilling
function Layout({ children }) {
  return <main className="container">{children}</main>
}

// ❌ ERRADO: Class components (legacy)
class UserCard extends React.Component { ... }

State Management

// ✅ Local state: useState
// Para estado de um componente

// ✅ Shared state: Context + useReducer
const AppContext = createContext<AppState | null>(null)

function AppProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  )
}

// ✅ 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+)

// ✅ Server Component (default) - async, data fetching
async function UserList() {
  const users = await db.users.findMany() // Direct DB access
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}

// ✅ Client Component - interactividade
'use client'
function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}

// ✅ Padrão: Server parent + Client children
// page.tsx (Server) → InteractiveSection.tsx ('use client')

Performance

// ✅ Lazy loading componentes
const HeavyComponent = lazy(() => import('./HeavyComponent'))

<Suspense fallback={<Loading />}>
  <HeavyComponent />
</Suspense>

// ✅ React.memo para componentes puros
const MemoizedCard = memo(function Card({ data }) {
  return <div>{data.title}</div>
})

// ✅ 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

function useDebounce<T>(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

function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    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

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(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

// Tab.tsx
const TabsContext = createContext<{
  activeTab: string;
  setActiveTab: (id: string) => void;
} | null>(null);

function Tabs({ children, defaultTab }: Props) {
  const [activeTab, setActiveTab] = useState(defaultTab);
  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabsContext.Provider>
  );
}

Tabs.List = function TabList({ children }: Props) {
  return <div className="tab-list">{children}</div>;
};

Tabs.Tab = function Tab({ id, children }: Props) {
  const { activeTab, setActiveTab } = useContext(TabsContext)!;
  return (
    <button
      className={activeTab === id ? 'active' : ''}
      onClick={() => setActiveTab(id)}
    >
      {children}
    </button>
  );
};

Tabs.Panel = function TabPanel({ id, children }: Props) {
  const { activeTab } = useContext(TabsContext)!;
  return activeTab === id ? <div>{children}</div> : null;
};

// Uso
<Tabs defaultTab="home">
  <Tabs.List>
    <Tabs.Tab id="home">Home</Tabs.Tab>
    <Tabs.Tab id="profile">Profile</Tabs.Tab>
  </Tabs.List>
  <Tabs.Panel id="home">Home content</Tabs.Panel>
  <Tabs.Panel id="profile">Profile content</Tabs.Panel>
</Tabs>

Render Props (legacy, preferir hooks)

// Evitar - usar custom hook
<DataFetcher url="/api/users" render={data => <UserList users={data} />} />

// Preferir
const { data } = useFetch('/api/users');
return <UserList users={data} />;

Composition Patterns (Vercel Engineering)

Padrões de composição para componentes React escaláveis. Fonte: Vercel composition-patterns.

Regra #1: Evitar Boolean Props (CRITICAL)

// ❌ ERRADO: Booleans duplicam estados possíveis
<Composer isThread isEditing={false} showAttachments showFormatting={false} />

// ✅ CORRECTO: Variantes explícitas
<ThreadComposer channelId="abc" />
<EditMessageComposer messageId="xyz" />
<ForwardMessageComposer messageId="123" />

Cada boolean duplica os estados possíveis. 5 booleans = 32 combinações, maioria impossível.

Regra #2: Compound Components com Context (HIGH)

// ✅ Compound Components: context partilhado, composição explícita
const ComposerContext = createContext<ComposerContextValue | null>(null)

function ComposerFrame({ children }: { children: React.ReactNode }) {
  return <form>{children}</form>
}

function ComposerInput() {
  const { state, actions: { update }, meta } = use(ComposerContext)
  return (
    <TextInput
      ref={meta.inputRef}
      value={state.input}
      onChangeText={(text) => 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
<Composer.Frame>
  <Composer.Input />
  <Composer.Footer>
    <Composer.Submit />
  </Composer.Footer>
</Composer.Frame>

Regra #3: State em Providers (HIGH)

// ❌ ERRADO: Estado preso dentro do componente
function ForwardComposer() {
  const [state, setState] = useState(initialState)
  return <Composer.Frame>...</Composer.Frame>
}
// 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 (
    <Composer.Provider
      state={state}
      actions={{ update: setState, submit }}
      meta={{ inputRef }}
    >
      {children}
    </Composer.Provider>
  )
}

// Agora QUALQUER componente dentro do Provider acede ao state
function ForwardDialog() {
  return (
    <ForwardProvider>
      <Dialog>
        <ForwardComposer />
        <MessagePreview />  {/* acede state via context */}
        <ForwardButton />   {/* acede submit via context */}
      </Dialog>
    </ForwardProvider>
  )
}

// Botão FORA do Composer.Frame mas DENTRO do Provider
function ForwardButton() {
  const { actions } = use(ComposerContext)
  return <Button onPress={actions.submit}>Forward</Button>
}

Princípio chave: O boundary do Provider é o que importa, não o nesting visual.

Regra #4: Interface Genérica para Dependency Injection (HIGH)

// ✅ 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<TextInput> }
}

// ✅ Múltiplos providers implementam a MESMA interface
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  return <Composer.Provider state={state} actions={{ update, submit }}>{children}</Composer.Provider>
}

function ForwardProvider({ children }) {
  const [state, setState] = useState(initialState)
  return <Composer.Provider state={state} actions={{ update: setState, submit: forward }}>{children}</Composer.Provider>
}

// 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)

// ❌ Render props (inflexível, difícil de ler)
<Composer
  renderHeader={() => <Header />}
  renderFooter={() => <><Formatting /><Emojis /></>}
/>

// ✅ Children (composição natural)
<Composer.Frame>
  <Header />
  <Composer.Input />
  <Composer.Footer>
    <Formatting />
    <Emojis />
  </Composer.Footer>
</Composer.Frame>

// Excepção: render props quando parent passa dados
<List data={items} renderItem={({ item }) => <Item item={item} />} />

Regra #6: React 19 APIs (MEDIUM)

// ✅ React 19: ref como prop normal (sem forwardRef)
function Input({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
  return <input ref={ref} {...props} />
}

// ✅ 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

// Pesquisar padrões React
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]