joabgonzalez

react

"Modern React with hooks and functional components. Trigger: When creating components, implementing hooks, managing state, or optimizing."

joabgonzalez 7 Updated 6mo ago

Resources

1
GitHub

Install

npx skillscat add joabgonzalez/ai-agents-skills/react

Install via the SkillsCat registry.

About this skill

This skill provides guidance for building React applications using modern functional components and hooks. It addresses common issues such as improper hook usage, stale closures, and unstable list keys that can lead to bugs and performance problems. Developers should use this skill when creating or refactoring React components, implementing hooks, managing state, or optimizing application performance.

SKILL.md

React Skill

Hooks, functional components, state management, and performance optimization for React apps.

When to Use

Use when:

  • Creating or refactoring React functional components
  • Implementing hooks (useState, useEffect, useMemo, useCallback)
  • Managing state, side effects, or performance optimization
  • Building component composition patterns

Don't use for:

  • Non-React JS (use javascript skill)
  • React Native (use react-native skill)
  • Redux (use redux-toolkit skill)
  • Server-side frameworks (use astro or relevant framework skill)

Critical Patterns

✅ REQUIRED: Functional Components with Hooks

// CORRECT: Functional component with hooks
const Counter: React.FC = () => {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
};

// WRONG: Class component (legacy)
class Counter extends React.Component {
  state = { count: 0 };
  render() { /* ... */ }
}

✅ REQUIRED: Proper useEffect Dependencies

// CORRECT: All dependencies included
useEffect(() => {
  fetchData(userId);
}, [userId]);

// WRONG: Missing dependencies (stale closures)
useEffect(() => {
  fetchData(userId);
}, []); // userId missing

✅ REQUIRED: Stable Keys for Lists

// CORRECT: Unique IDs
{items.map(item => <li key={item.id}>{item.name}</li>)}

// WRONG: Array index (bugs on reorder/delete)
{items.map((item, index) => <li key={index}>{item.name}</li>)}

❌ NEVER: Conditionally Call Hooks

// WRONG: Breaks React rules
if (condition) {
  const [value, setValue] = useState(0);
}

// CORRECT: Hooks at top level, conditional logic inside
const [value, setValue] = useState(0);
const shouldUse = condition ? value : defaultValue;

Decision Tree

  • **Simple state (<3 values)?** -> useState. See hooks-advanced.md (useState Patterns section).
  • Complex state (4+ related values)? -> useReducer. See hooks-advanced.md (useReducer Patterns section).
  • Side effect? -> useEffect with proper deps. See use-effect-patterns.md.
  • Data fetching? -> useEffect + AbortController. See use-effect-patterns.md (Async Patterns section).
  • Performance issue? -> Profile first with React DevTools. See performance.md.
  • Expensive computation? -> useMemo. See performance.md (useMemo section).
  • Callbacks to memoized children? -> useCallback. See performance.md (useCallback section).
  • Shared state across components? -> Context API or lift state. See context-patterns.md.
  • Compound component API? -> See context-patterns.md (Compound Components section).
  • Form with validation? -> Controlled components. See forms-state.md.
  • Multi-step form? -> Wizard pattern. See forms-state.md (Multi-Step Forms section).
  • File upload? -> Controlled input + File API. See forms-state.md (File Uploads section).
  • Large list (1000+)? -> Virtualization. See performance.md (List Rendering Optimization section).
  • Conditional rendering? -> && for simple, ternary for if-else, early return for complex logic.

Example

import { useState, useMemo } from 'react';

interface TodoProps {
  items: string[];
}

const TodoList: React.FC<TodoProps> = ({ items }) => {
  const [filter, setFilter] = useState('');

  const filteredItems = useMemo(() =>
    items.filter(item => item.toLowerCase().includes(filter.toLowerCase())),
    [items, filter]
  );

  return (
    <div>
      <input value={filter} onChange={(e) => setFilter(e.target.value)} />
      <ul>
        {filteredItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
};

Edge Cases

Stale closures in useEffect: Include all dependencies or use functional setState: setState(prev => prev + 1).

useEffect cleanup: Return cleanup for subscriptions, timers, listeners to prevent leaks:

useEffect(() => {
  const timer = setInterval(() => {}, 1000);
  return () => clearInterval(timer);
}, []);

Ref vs State: useRef for values that don't trigger re-renders (DOM refs, mutable values). useState for values that update UI.

Batching: React batches setState in event handlers. In async code, use flushSync for immediate updates (rare).

Children prop: Use React.ReactNode type. For render props: {(data) => <Component data={data} />}.

Architecture patterns: Apply Clean Architecture/SOLID only when AGENTS.md specifies it, codebase uses domain/application/infrastructure folders, or user requests. See architecture-patterns SKILL.md.

Checklist

  • Functional components with hooks (no class components)
  • All useEffect dependencies declared
  • Stable keys on list items (unique IDs, not indices)
  • No conditional hook calls
  • Cleanup returned from useEffect for subscriptions/timers
  • useMemo/useCallback only where profiling shows need
  • Controlled inputs for forms with validation
  • Context split by update frequency to avoid unnecessary re-renders

Resources