...
const HeaderTitle = () => ...
const HeaderActions = () => ...
// ✅ Consolidated component
type GameHeaderProps = {
title: string
subtitle: string
actions: ReactNode
}
export const GameHeader = ({ title, subtitle, actions }: GameHeaderProps) => (
(null)
export const GameProvider = ({ children }: { children: ReactNode }) => {
const gameState = useGameState()
return (
{children}
)
}
// Usage
```
### 3. Memoization for Performance
```typescript
// ✅ Memoize expensive components
export const Board = memo(({ cells, currentPiece }: BoardProps) => {
return (
{cells.map((row, y) => (
))}
)
})
// ✅ Memoize callbacks
const GameControls = () => {
const { movePiece, rotatePiece } = useGame()
const handleLeft = useCallback(() => {
movePiece('LEFT')
}, [movePiece])
const handleRotate = useCallback(() => {
rotatePiece()
}, [rotatePiece])
return (
)
}
```
### 4. Type-safe Props
```typescript
// ✅ 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 (
)
}
```
### 5. Dynamic IDs for Accessibility
```typescript
// ❌ Static IDs
export const FormField = ({ label }: FormFieldProps) => (
)
// ✅ Dynamic IDs with useId()
export const FormField = ({ label }: FormFieldProps) => {
const id = useId()
return (
)
}
```
## Custom Hooks Best Practices
### 1. Extract Reusable Logic
```typescript
// 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 ...
}
```
### 2. State Management Hooks
```typescript
// useLocalStorage hook
export const useLocalStorage = (
key: string,
initialValue: T
): [T, (value: T) => void] => {
const [storedValue, setStoredValue] = useState(() => {
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
```typescript
// ✅ Optimize with memo and useMemo
export const ExpensiveComponent = memo(({ data }: Props) => {
const processedData = useMemo(() => {
return expensiveCalculation(data)
}, [data])
return {processedData}
})
// ✅ Optimize callbacks with useCallback
const Parent = () => {
const [count, setCount] = useState(0)
const increment = useCallback(() => {
setCount((c) => c + 1)
}, [])
return
}
```
## 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"