New plugins: core-tools New skills: auto-expense, ticket-triage, design, security-check, aiktop-tasks, daily-digest, imap-triage, index-update, mindmap, notebooklm, proc-creator, tasks-overview, validate-component, perfex-module, report, calendar-manager New agents: design-critic, design-generator, design-lead, design-prompt-architect, design-researcher, compliance-auditor, metabase-analyst, gitea-integration-specialist Updated: all plugin configs, knowledge datasets, existing skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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).
Regra #48: Projectos React (incluindo Next.js) devem ser desenvolvidos no container dev (
server:"dev", path/root/Dev/<projecto>). 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
// ✅ 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__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
-
Análise Inicial
- Verificar requisitos e contexto
- Identificar ferramentas necessárias
-
Preparação
- Validar acesso a recursos
- Preparar ambiente de trabalho
-
Execução
- Executar operações de forma incremental
- Validar cada passo antes de prosseguir
-
Validação
- Verificar resultados obtidos
- Confirmar sucesso da operação
-
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]