skills/react-component-generator/SKILL.md
# React Component Generator --- name: "react-component-generator" description: "Generates React components following established conventions. Use when creating new React components, hooks, or when refactoring existing components to match standards." version: "1.0.0" --- ## Skill Purpose Generate React components and hooks that follow modern React patterns (React 19+), TypeScript best practices, and established codebase conventions. This skill ensures consistency, type safety, and adherence t
npx skillsauth add alienfast/claude skills/react-component-generatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate React components and hooks that follow modern React patterns (React 19+), TypeScript best practices, and established codebase conventions. This skill ensures consistency, type safety, and adherence to performance best practices.
Ask the user for:
// Define props interface
interface ComponentNameProps {
// Required props
requiredProp: string
// Optional props with default values
optionalProp?: number
// Event handlers
onAction?: (data: DataType) => void
// Children if needed
children?: React.ReactNode
}
import { useState, useEffect, useCallback } from 'react'
interface ComponentNameProps {
// Props interface here
}
export const ComponentName = ({
requiredProp,
optionalProp = defaultValue,
onAction,
}: ComponentNameProps) => {
// State declarations
const [state, setState] = useState<StateType>(initialValue)
// Effects with proper dependencies
useEffect(() => {
// Effect logic here
return () => {
// Cleanup logic
}
}, [dependencies])
// Event handlers with useCallback
const handleEvent = useCallback((param: ParamType) => {
// Handler logic
onAction?.(data)
}, [onAction])
// Render
return (
<div>
{/* Component JSX */}
</div>
)
}
interface GreetingProps {
name: string
greeting?: string
}
export const Greeting = ({ name, greeting = 'Hello' }: GreetingProps) => {
return <div>{greeting}, {name}!</div>
}
import { useState } from 'react'
interface CounterProps {
initialValue?: number
onCountChange?: (count: number) => void
}
export const Counter = ({ initialValue = 0, onCountChange }: CounterProps) => {
const [count, setCount] = useState(initialValue)
const increment = () => {
const newCount = count + 1
setCount(newCount)
onCountChange?.(newCount)
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
)
}
import { useReducer } from 'react'
interface FormState {
name: string
email: string
submitted: boolean
}
type FormAction =
| { type: 'UPDATE_NAME'; payload: string }
| { type: 'UPDATE_EMAIL'; payload: string }
| { type: 'SUBMIT' }
| { type: 'RESET' }
function formReducer(state: FormState, action: FormAction): FormState {
switch (action.type) {
case 'UPDATE_NAME':
return { ...state, name: action.payload }
case 'UPDATE_EMAIL':
return { ...state, email: action.payload }
case 'SUBMIT':
return { ...state, submitted: true }
case 'RESET':
return { name: '', email: '', submitted: false }
default:
return state
}
}
export const ContactForm = () => {
const [state, dispatch] = useReducer(formReducer, {
name: '',
email: '',
submitted: false,
})
return (
<form>
{/* Form implementation */}
</form>
)
}
import { useState, useEffect } from 'react'
interface UserDataProps {
userId: string
}
interface User {
id: string
name: string
email: string
}
export const UserData = ({ userId }: UserDataProps) => {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<Error | null>(null)
useEffect(() => {
if (!userId) return
let ignore = false
setLoading(true)
fetch(`/api/users/${userId}`)
.then((response) => response.json())
.then((data) => {
if (!ignore) {
setUser(data)
setLoading(false)
}
})
.catch((err) => {
if (!ignore) {
setError(err)
setLoading(false)
}
})
return () => {
ignore = true
}
}, [userId])
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!user) return <div>No user found</div>
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
)
}
Create a custom hook when:
import { useState, useEffect, useCallback } from 'react'
interface UseDataOptions {
initialValue?: DataType
onError?: (error: Error) => void
}
export const useData = (url: string, options: UseDataOptions = {}) => {
const [data, setData] = useState<DataType | null>(options.initialValue ?? null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<Error | null>(null)
const refetch = useCallback(() => {
if (!url) return
let ignore = false
setLoading(true)
setError(null)
fetch(url)
.then((response) => response.json())
.then((json) => {
if (!ignore) {
setData(json)
setLoading(false)
}
})
.catch((err) => {
if (!ignore) {
setError(err)
setLoading(false)
options.onError?.(err)
}
})
return () => {
ignore = true
}
}, [url, options.onError])
useEffect(() => {
refetch()
}, [refetch])
return { data, loading, error, refetch }
}
use if the hook calls other React hooksuseAuth, useChatRoom, useProductDatauseMount, useUnmount, useLifecycleuseCallback for performanceuseCallback dependenciesuseMemo dependencies// ✅ Correct
import { useState, useEffect, useCallback } from 'react'
// 🔴 Never use (legacy pattern)
import * as React from 'react'
import React from 'react'
When encountering legacy imports, always replace with named imports:
// Old code
import * as React from 'react'
const [state, setState] = React.useState(0)
// New code
import { useState } from 'react'
const [state, setState] = useState(0)
memo()import { memo } from 'react'
interface ExpensiveComponentProps {
data: ComplexData
onAction: (id: string) => void
}
export const ExpensiveComponent = memo(function ExpensiveComponent({
data,
onAction
}: ExpensiveComponentProps) {
// Component implementation
})
Use memo() when:
useCallback()const handleClick = useCallback((id: string) => {
// Handler logic
onItemClick?.(id)
}, [onItemClick])
Use useCallback() when:
useMemo()const sortedData = useMemo(() => {
return data.sort((a, b) => a.name.localeCompare(b.name))
}, [data])
Use useMemo() when:
Before completing component generation, verify:
import React from 'react')useEffect, useCallback, useMemouseCallback when passed to children or used as dependenciesonAction?.())exhaustive-deps)See React Rules for the complete anti-patterns list. All rules apply when generating components.
interface CardProps {
children: React.ReactNode
className?: string
}
const Card = ({ children, className }: CardProps) => {
return <div className={className}>{children}</div>
}
interface CardHeaderProps {
children: React.ReactNode
}
const CardHeader = ({ children }: CardHeaderProps) => {
return <div className="card-header">{children}</div>
}
interface CardBodyProps {
children: React.ReactNode
}
const CardBody = ({ children }: CardBodyProps) => {
return <div className="card-body">{children}</div>
}
Card.Header = CardHeader
Card.Body = CardBody
export { Card }
// Usage:
// <Card>
// <Card.Header>Title</Card.Header>
// <Card.Body>Content</Card.Body>
// </Card>
import { Component, ReactNode } from 'react'
interface ErrorBoundaryProps {
children: ReactNode
fallback?: ReactNode
}
interface ErrorBoundaryState {
hasError: boolean
error?: Error
}
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught by boundary:', error, errorInfo)
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? <div>Something went wrong.</div>
}
return this.props.children
}
}
Note: Error Boundaries are one of the few legitimate uses of class components, as React doesn't yet provide a hook-based alternative.
After generating a component:
For detailed rationale and advanced patterns, refer to:
/Users/kross/.claude/standards/react.md - Complete React standardstesting
End-to-end Linear issue macro — runs /start then /finish in sequence, gated on the /quality-review verdict. Worktree mode is opt-in via the `wt` token, mirroring /start. Pauses only for plan approval and the deferred-items filing decision; otherwise autonomous. Use when the user says 'full PL-XX', 'ship PL-XX end-to-end', or invokes /full.
development
Adversarial implementation review with triage and fix loop. Hard-gates on `pnpm check`, delegates to the quality-reviewer agent for categorized findings (Critical/High/Medium/Nice-to-Have/Approved), then triages and fixes findings via the developer agent. Loops until a re-review surfaces no new Critical/High/Medium findings (convergence), with a soft ceiling of 5 cycles before asking the user how to proceed; option 3 of that prompt terminates with verdict `escalated-to-architect`. Use when the user says 'review my work', 'check this implementation', 'adversarial review', 'quality review', or invokes /quality-review.
testing
Triage and prioritize Linear backlog. Analyzes issues for staleness, blockers, and suggests priorities based on dependencies and capacity.
testing
Start working on a Linear issue — check blockers, assign, move to In Progress, create branch, plan implementation, execute with checkpoint updates, review and triage findings. Use when the user says 'start issue', 'work on PL-XX', 'begin PL-XX', or invokes /start.