Generates modern React components with TypeScript, hooks, proper props typing, and best practices. Use when creating React components or scaffolding UI elements.
You are an expert at creating modern React components following current best practices.
Ask clarifying questions if not provided:
// ComponentName.tsx
import React, { useState, useEffect, useCallback } from 'react';
import styles from './ComponentName.module.css';
interface ComponentNameProps {
title: string;
onAction?: () => void;
items?: Item[];
className?: string;
children?: React.ReactNode;
}
export const ComponentName: React.FC<ComponentNameProps> = ({
title,
onAction,
items = [],
className = '',
children,
}) => {
// State
const [isLoading, setIsLoading] = useState(false);
// Effects
useEffect(() => {
// Side effects here
}, [dependencies]);
// Handlers
const handleClick = useCallback(() => {
if (onAction) {
onAction();
}
}, [onAction]);
// Render
return (
<div className={`${styles.container} ${className}`}>
<h2 className={styles.title}>{title}</h2>
{isLoading ? (
<div className={styles.loading}>Loading...</div>
) : (
<div className={styles.content}>
{children}
</div>
)}
</div>
);
};
ComponentName.displayName = 'ComponentName';
Styles File (ComponentName.module.css):
.container {
padding: 1rem;
border-radius: 0.5rem;
background-color: var(--background);
}
.title {
margin-bottom: 1rem;
font-size: 1.5rem;
font-weight: 600;
}
.content {
/* Content styles */
}
.loading {
display: flex;
justify-content: center;
padding: 2rem;
}
Test File (ComponentName.test.tsx):
import { render, screen, fireEvent } from '@testing-library/react';
import { ComponentName } from './ComponentName';
describe('ComponentName', () => {
it('renders with required props', () => {
render(<ComponentName title="Test Title" />);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('calls onAction when clicked', () => {
const handleAction = jest.fn();
render(<ComponentName title="Test" onAction={handleAction} />);
fireEvent.click(screen.getByRole('button'));
expect(handleAction).toHaveBeenCalledTimes(1);
});
});
Barrel Export (index.ts):
export { ComponentName } from './ComponentName';
export type { ComponentNameProps } from './ComponentName';
TypeScript:
Component Structure:
Performance:
Accessibility:
File Organization:
ComponentName/
├── ComponentName.tsx # Component logic
├── ComponentName.module.css # Styles
├── ComponentName.test.tsx # Tests
├── ComponentName.stories.tsx # Storybook (optional)
└── index.ts # Barrel export
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
label,
onClick,
variant = 'primary',
disabled = false,
}) => (
<button
className={styles[variant]}
onClick={onClick}
disabled={disabled}
>
{label}
</button>
);
export const UserList: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
return (
<ul>
{users.map(user => (
<UserListItem key={user.id} user={user} />
))}
</ul>
);
};
interface FormData {
email: string;
password: string;
}
export const LoginForm: React.FC = () => {
const [formData, setFormData] = useState<FormData>({
email: '',
password: '',
});
const [errors, setErrors] = useState<Partial<FormData>>({});
const validate = (): boolean => {
const newErrors: Partial<FormData> = {};
if (!formData.email.includes('@')) {
newErrors.email = 'Invalid email';
}
if (formData.password.length < 8) {
newErrors.password = 'Password too short';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (validate()) {
// Submit form
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
/>
{errors.email && <span className={styles.error}>{errors.email}</span>}
<button type="submit">Login</button>
</form>
);
};
After creating component, provide:
npx skills add Dexploarer/react-component-generator下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer