一键导入
react-component-structure
Best practices for structuring React components - function declarations, file organization, and Single Responsibility Principle
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Best practices for structuring React components - function declarations, file organization, and Single Responsibility Principle
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | React Component Structure |
| description | Best practices for structuring React components - function declarations, file organization, and Single Responsibility Principle |
Best practices for structuring React components for readability, testability, and maintainability.
Always use function declarations for components, not const with arrow functions.
const UserProfile = ({ name, email }: Props) => {
return (
<div>
<h1>{name}</h1>
<p>{email}</p>
</div>
)
}
// Or worse
const UserProfile: React.FC<Props> = ({ name, email }) => {
return (
<div>
<h1>{name}</h1>
<p>{email}</p>
</div>
)
}
function UserProfile({ name, email }: Props) {
return (
<div>
<h1>{name}</h1>
<p>{email}</p>
</div>
);
}
children (often unwanted)ReactNode which includes undefined (allows accidental undefined returns)Components should do one thing well. Avoid mixing concerns or creating "god components".
📖 For comprehensive SOLID principles including SRP, see: code-standards/rules/solid-principles.md
In React context, SRP means:
// File: UserProfile.tsx
function formatDate(date: Date): string {
return new Intl.DateTimeFormat('nl-NL').format(date);
}
function calculateAge(birthDate: Date): number {
const today = new Date();
const age = today.getFullYear() - birthDate.getFullYear();
return age;
}
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function formatPhoneNumber(phone: string): string {
return phone.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
}
function capitalizeWords(str: string): string {
return str.replace(/\b\w/g, (l) => l.toUpperCase());
}
// Finally, the component (after 5 helpers!)
function UserProfile({ user }: Props) {
return (
<div>
<h1>{capitalizeWords(user.name)}</h1>
<p>Age: {calculateAge(user.birthDate)}</p>
<p>Email: {user.email}</p>
<p>Phone: {formatPhoneNumber(user.phone)}</p>
</div>
);
}
// File: UserProfile.tsx
import { calculateAge, formatDate } from '@/utils/date-helpers';
import { formatPhoneNumber } from '@/utils/formatters';
import { capitalizeWords } from '@/utils/string-helpers';
import { validateEmail } from '@/utils/validators';
function UserProfile({ user }: Props) {
return (
<div>
<h1>{capitalizeWords(user.name)}</h1>
<p>Age: {calculateAge(user.birthDate)}</p>
<p>Email: {user.email}</p>
<p>Phone: {formatPhoneNumber(user.phone)}</p>
</div>
);
}
For component-specific helpers that are short (1-3 lines):
// File: UserCard.tsx
function UserCard({ user, onEdit }: Props) {
const displayName = formatDisplayName(user.firstName, user.lastName);
const initials = getInitials(user.firstName, user.lastName);
return (
<div>
<Avatar>{initials}</Avatar>
<h2>{displayName}</h2>
<button onClick={() => onEdit(user.id)}>Edit</button>
</div>
);
}
// Simple, component-specific helpers placed AFTER
function formatDisplayName(first: string, last: string): string {
return `${first} ${last}`;
}
function getInitials(first: string, last: string): string {
return `${first[0]}${last[0]}`.toUpperCase();
}
Recommended file structure:
// 1. Imports (external first, then internal)
import { formatCurrency } from '@/utils/formatters';
import { useEffect, useState } from 'react';
// 2. Constants (if needed)
const DISCOUNT_THRESHOLD = 100;
// 3. Types/Interfaces (as close as possible to component)
interface ProductCardProps {
product: Product;
onAddToCart: (id: string) => void;
}
// 4. Main component
function ProductCard({ product, onAddToCart }: ProductCardProps) {
const [quantity, setQuantity] = useState(1);
const discountedPrice = calculateDiscount(product.price, quantity);
return (
<div>
<h3>{product.name}</h3>
<p>{formatCurrency(discountedPrice)}</p>
<button onClick={() => onAddToCart(product.id)}>Add to Cart</button>
</div>
);
}
// 5. Component-specific helpers (if simple and tightly coupled)
function calculateDiscount(price: number, qty: number): number {
return qty >= DISCOUNT_THRESHOLD ? price * 0.9 : price;
}
// 6. Export
export { ProductCard };
function Dashboard() {
// 300 lines of logic handling:
// - User authentication
// - Data fetching
// - Filtering
// - Sorting
// - Pagination
// - Charts rendering
// - Form handling
return <>{/* 200 lines of JSX */}</>;
}
function Dashboard() {
return (
<DashboardLayout>
<UserHeader />
<FilterControls />
<DataTable />
<ChartSection />
</DashboardLayout>
);
}
function ProductList() {
// Data fetching, filtering, sorting, pagination
const [products, setProducts] = useState([]);
const [filters, setFilters] = useState({});
// ... 50 lines of logic
return <>{/* Presentation */}</>;
}
function ProductList() {
const { products, isLoading } = useProducts(); // Custom hook for logic
if (isLoading) {
return <LoadingSpinner />;
}
return <ProductGrid products={products} />;
}
| Aspect | Guideline |
|---|---|
| Component syntax | Function declarations, not const |
| React.FC | Avoid (unnecessary, has pitfalls) |
| Helpers | Extract to utils if reused or complex |
| Component size | Keep focused (~50-100 lines) |
| Organization | Imports → Constants → Props → Component → Helpers → Export |
| Props location | Define immediately before component |
| Single Responsibility | One component, one purpose |
Principle: Components should be easy to understand at a glance. If you have to scroll past 5 helpers to find the component, refactor.
Code standards and conventions for React, TypeScript, and domain-driven front-end architecture
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Comprehensive testing guidelines for Vitest with React Testing Library
Conventional commit format and workflow with Jira ticket integration