agentleFS
peopleforresterpeopleforrester/claude-dotfiles/skills/frameworks/react-patterns/SKILL.md

react-patterns

Skill3 starsChanged 7 months agoMITView on GitHub

React 19+ best practices and patterns. Covers hooks, composition, server components, performance optimization, and state management. Use when building React components or reviewing React code.

Files
SKILL.md

React Patterns

Modern React 19+ patterns and best practices.

Component Patterns

Composition Over Prop Drilling

// Compose with children instead of passing many props
<Card>
  <Card.Header>
    <Card.Title>User Profile</Card.Title>
  </Card.Header>
  <Card.Body>
    <UserInfo user={user} />
  </Card.Body>
  <Card.Footer>
    <Button onClick={save}>Save</Button>
  </Card.Footer>
</Card>

Render Props for Flexibility

interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => ReactNode;
  keyExtractor: (item: T) => string;
}

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        <li key={keyExtractor(item)}>{renderItem(item, i)}</li>
      ))}
    </ul>
  );
}

Hook Patterns

Custom Data Fetching Hook

function useQuery<T>(key: string, fetcher: () => Promise<T>) {
  const [state, setState] = useState<{
    data: T | null;
    error: Error | null;
    isLoading: boolean;
  }>({ data: null, error: null, isLoading: true });

  useEffect(() => {
    let cancelled = false;
    setState(prev => ({ ...prev, isLoading: true }));

    fetcher()
      .then(data => { if (!cancelled) setState({ data, error: null, isLoading: false }); })
      .catch(error => { if (!cancelled) setState({ data: null, error, isLoading: false }); });

    return () => { cancelled = true; };
  }, [key]);

  return state;
}

useCallback for Stable References

const handleSubmit = useCallback(
  async (data: FormData) => {
    await api.submit(userId, data);
    onSuccess();
  },
  [userId, onSuccess]
);

useMemo for Expensive Computations

const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
  [items]
);

State Management

Local State First

// Start simple
const [isOpen, setIsOpen] = useState(false);

// Graduate to useReducer for complex state
const [state, dispatch] = useReducer(cartReducer, initialCart);

// Context for cross-component state
const ThemeContext = createContext<Theme>('light');

Server State (React Query / SWR)

const { data, isLoading } = useQuery({
  queryKey: ['users', userId],
  queryFn: () => fetchUser(userId),
  staleTime: 5 * 60 * 1000,
});

Performance

Code Splitting

const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Skeleton />}>
      <Dashboard />
    </Suspense>
  );
}

Virtualization for Long Lists

import { useVirtualizer } from '@tanstack/react-virtual';

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null);
  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
  });

  return (
    <div ref={parentRef} style={{ overflow: 'auto', height: 400 }}>
      {virtualizer.getVirtualItems().map(row => (
        <div key={row.key} style={{ transform: `translateY(${row.start}px)` }}>
          {items[row.index].name}
        </div>
      ))}
    </div>
  );
}

Error Boundaries

class ErrorBoundary extends Component<Props, { hasError: boolean }> {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) return this.props.fallback;
    return this.props.children;
  }
}

Checklist

  • Functional components only (no class components for new code)
  • Custom hooks for reusable stateful logic
  • Correct dependency arrays in useEffect/useCallback/useMemo
  • Error boundaries at route level
  • Loading and error states handled for async data
  • Accessibility: ARIA labels, keyboard navigation, focus management
  • Code splitting for route-level components
  • Keys use stable, unique identifiers (not array index)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.