home / skills / doanchienthangdev / omgkit / react

This skill helps you build production React applications with hooks, TypeScript, and performance optimization across components and UIs.

npx playbooks add skill doanchienthangdev/omgkit --skill react

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.2 KB
---
name: building-react-apps
description: Builds production React applications with hooks, TypeScript, state management, and performance optimization. Use when creating React SPAs, component systems, or interactive UIs.
---

# React

## Quick Start

```tsx
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}
```

## Features

| Feature | Description | Guide |
|---------|-------------|-------|
| Hooks | useState, useEffect, custom hooks | [HOOKS.md](HOOKS.md) |
| TypeScript | Props, state, event typing | [TYPESCRIPT.md](TYPESCRIPT.md) |
| State | Zustand, Context, useReducer | [STATE.md](STATE.md) |
| Forms | React Hook Form, Zod validation | [FORMS.md](FORMS.md) |
| Testing | Vitest, Testing Library | [TESTING.md](TESTING.md) |
| Performance | memo, useMemo, useCallback, Suspense | [PERFORMANCE.md](PERFORMANCE.md) |

## Common Patterns

### Typed Component with Props

```tsx
interface UserCardProps {
  user: { id: string; name: string; email: string };
  onEdit: (user: UserCardProps['user']) => void;
  onDelete: (id: string) => void;
}

function UserCard({ user, onEdit, onDelete }: UserCardProps) {
  return (
    <div className="user-card">
      <h3>{user.name}</h3>
      <p>{user.email}</p>
      <button onClick={() => onEdit(user)}>Edit</button>
      <button onClick={() => onDelete(user.id)}>Delete</button>
    </div>
  );
}
```

### Custom Hook for Data Fetching

```tsx
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(() => {
    let cancelled = false;

    async function fetchData() {
      try {
        const res = await fetch(url);
        const json = await res.json();
        if (!cancelled) setData(json);
      } catch (e) {
        if (!cancelled) setError(e as Error);
      } finally {
        if (!cancelled) setLoading(false);
      }
    }

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

  return { data, loading, error };
}
```

### Form with Validation

```tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(schema),
  });

  const onSubmit = (data: z.infer<typeof schema>) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}
      <input {...register('password')} type="password" />
      {errors.password && <span>{errors.password.message}</span>}
      <button type="submit">Login</button>
    </form>
  );
}
```

## Workflows

### Component Development

1. Define props interface with TypeScript
2. Create component with hooks
3. Extract reusable logic to custom hooks
4. Add error boundaries for fault isolation
5. Write tests with Testing Library

### State Management Decision

```
Local state only       -> useState
Complex local state    -> useReducer
Shared across tree     -> Context + useReducer
App-wide state         -> Zustand/Redux
Server state           -> TanStack Query
```

## Best Practices

| Do | Avoid |
|----|-------|
| Use functional components | Class components |
| Extract custom hooks | Duplicating effect logic |
| Memoize expensive computations | Premature optimization |
| Handle loading/error states | Assuming success |
| Use keys for lists | Index as key for dynamic lists |

## Project Structure

```
src/
├── App.tsx
├── main.tsx
├── components/         # Reusable UI components
├── hooks/              # Custom hooks
├── pages/              # Route components
├── stores/             # State management
├── services/           # API calls
├── utils/              # Helper functions
└── types/              # TypeScript types
```

For detailed examples and patterns, see reference files above.

Overview

This skill builds production-ready React applications using hooks, TypeScript, modern state management, and performance optimizations. It provides patterns, components, and workflows for single-page apps, component systems, and interactive UIs. The focus is practical: typed components, custom hooks, form validation, testing, and state decisions for scalable projects.

How this skill works

The skill codifies common React patterns: typed component props, custom data-fetching hooks, and validated forms using React Hook Form + Zod. It recommends state strategies (useState, useReducer, Context, Zustand) and performance tools (memo, useMemo, useCallback, Suspense). Project structure, testing approaches, and development workflows are included to accelerate delivery of robust apps.

When to use it

  • Building a new React SPA with TypeScript and strict typing
  • Creating a reusable component library or design system
  • Implementing client-side forms with validation and error handling
  • Choosing a state management strategy for small to large apps
  • Optimizing render performance and preventing unnecessary re-renders

Best practices

  • Prefer functional components and extract reusable logic into custom hooks
  • Type props and state with TypeScript to catch errors at compile time
  • Select state tools by scope: useState/useReducer -> Context -> Zustand/Redux
  • Handle loading and error states explicitly; avoid optimistic assumptions
  • Memoize expensive computations selectively; avoid premature optimization

Example use cases

  • A dashboard SPA using TypeScript, Zustand for app-wide state, and TanStack Query for server state
  • A user management component set with typed UserCard components and tested UI
  • A login form using React Hook Form and Zod for schema validation and clear error messages
  • A data-driven page using a custom useFetch hook with cancellation and loading states
  • Performance-tuned list rendering using keys, memo, and virtualization for large datasets

FAQ

When should I use useReducer instead of useState?

Use useReducer for complex local state updates or when state transitions are easier to express as actions. It improves predictability and makes complex updates easier to test.

How do I choose between Context and a global store like Zustand?

Use Context for lightweight shared state scoped to a subtree. Use Zustand or Redux for app-wide state with frequent updates or when you need more advanced features like middleware or persistence.