react-component-design

sakataka's avatarfrom sakataka

Design React components following Tetris architecture guidelines. Use when creating new components, refactoring components, optimizing performance, or improving component structure. Auto-triggers on phrases like "create a component", "refactor this component", "optimize rendering", or "improve component design". Emphasizes component consolidation, unified patterns, and efficient hook usage.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 2, 2026

When & Why to Use This Skill

This Claude skill automates the creation and refactoring of React components according to the Tetris architecture guidelines. It ensures code quality by enforcing functional component patterns, TypeScript type safety, and performance optimization techniques like memoization and custom hook extraction.

Use Cases

  • Generating new React functional components with standardized TypeScript 'type' aliases and built-in i18n support.
  • Refactoring fragmented or legacy class components into consolidated, modern functional structures to reduce technical debt.
  • Optimizing application rendering performance by implementing React.memo, useMemo, and useCallback patterns to minimize re-renders.
  • Improving web accessibility (A11y) by automatically integrating dynamic IDs using the useId hook for form fields and UI elements.
  • Extracting complex component logic into reusable custom hooks to simplify state management and enhance code reusability.
namereact-component-design
descriptionDesign React components following Tetris architecture guidelines. Use when creating new components, refactoring components, optimizing performance, or improving component structure. Auto-triggers on phrases like "create a component", "refactor this component", "optimize rendering", or "improve component design". Emphasizes component consolidation, unified patterns, and efficient hook usage.
allowed-toolsRead, Edit, Grep, Glob

React Component Design Guide

Design patterns for React components in the Tetris project.

Core Principles

  1. Component Consolidation: Prefer unified components over excessive fragmentation
  2. Functional Components: No class components
  3. Custom Hooks: Extract reusable logic
  4. Type Aliases: Use type instead of interface for props
  5. Dynamic IDs: Use useId() hook for accessibility
  6. Optimized Patterns: Minimize re-renders and prop drilling

Component Structure

Basic Component Template

import { useId } from 'react'
import { useTranslation } from 'react-i18next'

type GameButtonProps = {
  onClick: () => void
  label: string
  disabled?: boolean
}

export const GameButton = ({ onClick, label, disabled = false }: GameButtonProps) => {
  const { t } = useTranslation()
  const id = useId()

  return (
    <button
      id={id}
      onClick={onClick}
      disabled={disabled}
      className="game-button"
    >
      {t(label)}
    </button>
  )
}

Component with Custom Hook

// Custom hook for game logic
const useGameState = () => {
  const [board, setBoard] = useState<Board>(createBoard())
  const [currentPiece, setCurrentPiece] = useState<Piece | null>(null)
  const [score, setScore] = useState(0)

  const placePiece = useCallback((position: Position) => {
    if (!currentPiece) return

    const result = tryPlacePiece(board, currentPiece, position)
    if (result.ok) {
      setBoard(result.value.board)
      setScore((s) => s + result.value.points)
    }
  }, [board, currentPiece])

  return { board, currentPiece, score, placePiece }
}

// Component using the hook
export const GameBoard = () => {
  const { board, currentPiece, score, placePiece } = useGameState()

  return (
    <div className="game-board">
      <Board data={board} currentPiece={currentPiece} />
      <Score value={score} />
    </div>
  )
}

Design Patterns

1. Component Consolidation

// ❌ Excessive fragmentation
const Header = () => <div className="header">...</div>
const HeaderTitle = () => <h1>...</h1>
const HeaderSubtitle = () => <p>...</p>
const HeaderActions = () => <div>...</div>

// ✅ Consolidated component
type GameHeaderProps = {
  title: string
  subtitle: string
  actions: ReactNode
}

export const GameHeader = ({ title, subtitle, actions }: GameHeaderProps) => (
  <header className="game-header">
    <div>
      <h1>{title}</h1>
      <p>{subtitle}</p>
    </div>
    <div className="actions">{actions}</div>
  </header>
)

2. Composition over Props Drilling

// ❌ Props drilling
<Game>
  <Board score={score} level={level} />
  <Controls score={score} level={level} />
  <Stats score={score} level={level} />
</Game>

// ✅ Context for shared state
const GameStateContext = createContext<GameState | null>(null)

export const GameProvider = ({ children }: { children: ReactNode }) => {
  const gameState = useGameState()
  return (
    <GameStateContext.Provider value={gameState}>
      {children}
    </GameStateContext.Provider>
  )
}

// Usage
<GameProvider>
  <Board />
  <Controls />
  <Stats />
</GameProvider>

3. Memoization for Performance

// ✅ Memoize expensive components
export const Board = memo(({ cells, currentPiece }: BoardProps) => {
  return (
    <div className="board">
      {cells.map((row, y) => (
        <Row key={y} cells={row} y={y} currentPiece={currentPiece} />
      ))}
    </div>
  )
})

// ✅ Memoize callbacks
const GameControls = () => {
  const { movePiece, rotatePiece } = useGame()

  const handleLeft = useCallback(() => {
    movePiece('LEFT')
  }, [movePiece])

  const handleRotate = useCallback(() => {
    rotatePiece()
  }, [rotatePiece])

  return (
    <div>
      <button onClick={handleLeft}>{t('controls.left')}</button>
      <button onClick={handleRotate}>{t('controls.rotate')}</button>
    </div>
  )
}

4. Type-safe Props

// ✅ Use type aliases (not interface)
type ButtonVariant = 'primary' | 'secondary' | 'danger'

type ButtonProps = {
  variant: ButtonVariant
  size?: 'small' | 'medium' | 'large'
  onClick: () => void
  children: ReactNode
  disabled?: boolean
}

export const Button = ({
  variant,
  size = 'medium',
  onClick,
  children,
  disabled = false
}: ButtonProps) => {
  const className = cn(
    'button',
    `button--${variant}`,
    `button--${size}`,
    disabled && 'button--disabled'
  )

  return (
    <button className={className} onClick={onClick} disabled={disabled}>
      {children}
    </button>
  )
}

5. Dynamic IDs for Accessibility

// ❌ Static IDs
export const FormField = ({ label }: FormFieldProps) => (
  <div>
    <label htmlFor="game-input">{label}</label>
    <input id="game-input" />
  </div>
)

// ✅ Dynamic IDs with useId()
export const FormField = ({ label }: FormFieldProps) => {
  const id = useId()

  return (
    <div>
      <label htmlFor={id}>{label}</label>
      <input id={id} />
    </div>
  )
}

Custom Hooks Best Practices

1. Extract Reusable Logic

// useKeyPress hook
export const useKeyPress = (targetKey: string, callback: () => void) => {
  useEffect(() => {
    const handleKeyPress = (event: KeyboardEvent) => {
      if (event.key === targetKey) {
        callback()
      }
    }

    window.addEventListener('keydown', handleKeyPress)
    return () => {
      window.removeEventListener('keydown', handleKeyPress)
    }
  }, [targetKey, callback])
}

// Usage in component
const GameControls = () => {
  const { movePiece } = useGame()

  useKeyPress('ArrowLeft', () => movePiece('LEFT'))
  useKeyPress('ArrowRight', () => movePiece('RIGHT'))
  useKeyPress(' ', () => movePiece('DROP'))

  return <div>...</div>
}

2. State Management Hooks

// useLocalStorage hook
export const useLocalStorage = <T,>(
  key: string,
  initialValue: T
): [T, (value: T) => void] => {
  const [storedValue, setStoredValue] = useState<T>(() => {
    const item = localStorage.getItem(key)
    return item ? JSON.parse(item) : initialValue
  })

  const setValue = useCallback((value: T) => {
    setStoredValue(value)
    localStorage.setItem(key, JSON.stringify(value))
  }, [key])

  return [storedValue, setValue]
}

// Usage
const [highScore, setHighScore] = useLocalStorage('tetris:highScore', 0)

Component Checklist

  • Functional component (no classes)
  • Type alias for props (not interface)
  • i18n for all user-facing strings
  • useId() for dynamic IDs
  • Custom hooks for reusable logic
  • Memoization where appropriate
  • Minimal prop drilling (use context)
  • Consolidated (not overly fragmented)

Performance Optimization

// ✅ Optimize with memo and useMemo
export const ExpensiveComponent = memo(({ data }: Props) => {
  const processedData = useMemo(() => {
    return expensiveCalculation(data)
  }, [data])

  return <div>{processedData}</div>
})

// ✅ Optimize callbacks with useCallback
const Parent = () => {
  const [count, setCount] = useState(0)

  const increment = useCallback(() => {
    setCount((c) => c + 1)
  }, [])

  return <Child onIncrement={increment} />
}

When This Skill Activates

  • "Create a new component"
  • "Refactor this component"
  • "Optimize component performance"
  • "Improve component structure"
  • "Extract logic to custom hook"
  • "Reduce re-renders"

Advanced Patterns

See component-patterns.md for:

  • Advanced composition patterns
  • Custom hook recipes
  • Performance optimization strategies
  • Accessibility best practices