code-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Frontend Code Review

前端代码评审

This skill provides comprehensive, production-ready code review for modern frontend applications with actionable feedback focused on React/TypeScript/Tailwind stack.
本技能为基于React/TypeScript/Tailwind技术栈的现代前端应用提供全面、可用于生产环境的代码评审,并给出可执行的反馈建议。

Purpose

用途

Transform frontend code review from manual inspection into systematic analysis covering:
  1. Frontend Security - XSS, CSRF, sensitive data exposure, auth issues
  2. React Performance - Re-renders, memoization, bundle size, lazy loading
  3. Code Quality - Readability, maintainability, React best practices
  4. Component Architecture - Layered architecture, separation of concerns, reusability
  5. Type Safety - TypeScript usage, type correctness, runtime validation
  6. Accessibility - WCAG compliance, keyboard navigation, screen readers
  7. Responsive Design - Mobile-first, breakpoints, Tailwind patterns
  8. SEO & Meta - Meta tags, semantic HTML, performance metrics
  9. Testing - Component tests, hooks tests, edge cases
  10. State Management - Zustand/Context patterns, React Query usage
将前端代码评审从人工检查转变为系统化分析,涵盖以下维度:
  1. 前端安全 - XSS、CSRF、敏感数据泄露、认证问题
  2. React性能 - 重渲染、记忆化、包体积、懒加载
  3. 代码质量 - 可读性、可维护性、React最佳实践
  4. 组件架构 - 分层架构、关注点分离、可复用性
  5. 类型安全 - TypeScript使用、类型正确性、运行时验证
  6. 可访问性 - WCAG合规、键盘导航、屏幕阅读器适配
  7. 响应式设计 - 移动优先、断点设置、Tailwind模式
  8. SEO与元信息 - 元标签、语义化HTML、性能指标
  9. 测试 - 组件测试、Hooks测试、边缘场景
  10. 状态管理 - Zustand/Context模式、React Query使用

When to Use This Skill

适用场景

Use this skill when:
  • User asks for code review or feedback
  • User mentions: "review", "check", "feedback", "quality", "security"
  • After generating components or features
  • User asks about performance or accessibility
  • Before committing major changes
  • Examples:
    • "Review this component"
    • "Is this React code optimized?"
    • "Can you check for accessibility issues?"
    • "How can I improve this?"
    • "Review my feature implementation"
当以下情况时使用本技能:
  • 用户请求代码评审或反馈
  • 用户提及:"review"、"check"、"feedback"、"quality"、"security"(评审、检查、反馈、质量、安全)
  • 生成组件或功能后
  • 用户询问性能或可访问性相关问题
  • 提交重大变更前
  • 示例:
    • "评审这个组件"
    • "这段React代码是否经过优化?"
    • "你能检查一下可访问性问题吗?"
    • "我该如何改进这段代码?"
    • "评审我的功能实现"

Review Process

评审流程

Step 1: Understand Context

步骤1:了解上下文

Before reviewing, gather context:
  1. Code Type:
    • React Component (UI, Form, List, etc.)
    • Custom Hook (business logic)
    • Utility function (helpers, transforms)
    • API integration (React Query, fetch)
    • Store/State management (Zustand, Context)
    • Styling (Tailwind, CSS-in-JS)
  2. Review Scope:
    • Single component/hook
    • Entire feature (multiple files)
    • Page/route implementation
    • Shared utilities
  3. Priority:
    • Security-critical (auth, payment forms)
    • Performance-critical (large lists, complex calculations)
    • User-facing (accessibility, UX)
    • Internal (utilities, helpers)
在评审前,先收集以下上下文信息:
  1. 代码类型
    • React组件(UI、表单、列表等)
    • 自定义Hook(业务逻辑)
    • 工具函数(辅助函数、转换函数)
    • API集成(React Query、fetch)
    • 存储/状态管理(Zustand、Context)
    • 样式(Tailwind、CSS-in-JS)
  2. 评审范围
    • 单个组件/Hook
    • 完整功能(多文件)
    • 页面/路由实现
    • 共享工具函数
  3. 优先级
    • 安全关键型(认证、支付表单)
    • 性能关键型(大型列表、复杂计算)
    • 用户面向型(可访问性、用户体验)
    • 内部工具型(工具函数、辅助组件)

Step 2: Initial Scan

步骤2:初步扫描

Quickly scan for obvious issues:
Critical Issues (🚨 CRITICAL):
  • XSS vulnerabilities (dangerouslySetInnerHTML)
  • CSRF vulnerabilities (missing tokens)
  • Sensitive data exposure (tokens in localStorage)
  • Authentication bypass
  • Hardcoded secrets/API keys
High Priority (⚠️ HIGH):
  • Performance bottlenecks (unnecessary re-renders, no memoization)
  • Memory leaks (missing cleanup in useEffect)
  • Error handling gaps
  • Accessibility violations (no ARIA labels, keyboard support)
  • Missing input validation
<br>Medium Priority (⚡ MEDIUM):
  • Code duplication
  • Unclear component/variable names
  • Missing loading/error states
  • Poor TypeScript usage (any types)
  • Inconsistent Tailwind usage
Low Priority (💡 LOW):
  • Code style inconsistencies
  • Missing comments for complex logic
  • Minor optimizations
  • Documentation gaps
快速扫描明显问题:
严重问题(🚨 严重)
  • XSS漏洞(dangerouslySetInnerHTML)
  • CSRF漏洞(缺少令牌)
  • 敏感数据泄露(localStorage中存储令牌)
  • 认证绕过
  • 硬编码密钥/API密钥
高优先级问题(⚠️ 高)
  • 性能瓶颈(不必要的重渲染、未使用记忆化)
  • 内存泄漏(useEffect中缺少清理逻辑)
  • 错误处理缺失
  • 可访问性违规(无ARIA标签、无键盘支持)
  • 缺少输入验证
中优先级问题(⚡ 中)
  • 代码重复
  • 组件/变量命名不清晰
  • 缺少加载/错误状态
  • TypeScript使用不当(any类型)
  • Tailwind使用不一致
低优先级问题(💡 低)
  • 代码风格不一致
  • 复杂逻辑缺少注释
  • 次要优化点
  • 文档缺失

Step 3: Deep Analysis

步骤3:深度分析

3.1 前端安全评审

Perform systematic review across all dimensions:
检查常见前端漏洞:
typescript
// ❌ BAD: XSS vulnerability
function UserComment({ comment }: { comment: string }) {
  return <div dangerouslySetInnerHTML={{ __html: comment }} />;
}

// ✅ GOOD: Sanitized HTML
import DOMPurify from 'dompurify';

function UserComment({ comment }: { comment: string }) {
  return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(comment) }} />;
}

// ✅ BETTER: No HTML, just text
function UserComment({ comment }: { comment: string }) {
  return <div>{comment}</div>;
}

// ❌ BAD: Token in localStorage (XSS vulnerable)
localStorage.setItem('token', response.token);

// ✅ GOOD: HttpOnly cookie (set by server)
// Or use secure session management library

// ❌ BAD: Hardcoded API key
const API_KEY = "pk_live_abc123xyz";

// ✅ GOOD: Environment variable
const API_KEY = process.env.NEXT_PUBLIC_API_KEY;

// ❌ BAD: No CSRF protection
async function transferMoney(to: string, amount: number) {
  await fetch('/api/transfer', {
    method: 'POST',
    body: JSON.stringify({ to, amount })
  });
}

// ✅ GOOD: Include CSRF token
async function transferMoney(to: string, amount: number) {
  const csrfToken = getCsrfToken();
  await fetch('/api/transfer', {
    method: 'POST',
    headers: {
      'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify({ to, amount })
  });
}
前端安全检查清单:
  • 未在用户输入中使用
    dangerouslySetInnerHTML
  • 未在localStorage中存储敏感令牌
  • 无硬编码API密钥或机密信息
  • 状态变更操作具备CSRF防护
  • 所有表单输入均有验证
  • 用户生成内容已做输出清理
  • 生产环境强制使用HTTPS
  • 控制台日志中无敏感数据
  • 受保护路由有正确的认证检查
  • 安全的密码输入(敏感字段无自动补全)

3.1 Frontend Security Review

3.2 React性能评审

Check against common frontend vulnerabilities:
typescript
// ❌ BAD: XSS vulnerability
function UserComment({ comment }: { comment: string }) {
  return <div dangerouslySetInnerHTML={{ __html: comment }} />;
}

// ✅ GOOD: Sanitized HTML
import DOMPurify from 'dompurify';

function UserComment({ comment }: { comment: string }) {
  return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(comment) }} />;
}

// ✅ BETTER: No HTML, just text
function UserComment({ comment }: { comment: string }) {
  return <div>{comment}</div>;
}

// ❌ BAD: Token in localStorage (XSS vulnerable)
localStorage.setItem('token', response.token);

// ✅ GOOD: HttpOnly cookie (set by server)
// Or use secure session management library

// ❌ BAD: Hardcoded API key
const API_KEY = "pk_live_abc123xyz";

// ✅ GOOD: Environment variable
const API_KEY = process.env.NEXT_PUBLIC_API_KEY;

// ❌ BAD: No CSRF protection
async function transferMoney(to: string, amount: number) {
  await fetch('/api/transfer', {
    method: 'POST',
    body: JSON.stringify({ to, amount })
  });
}

// ✅ GOOD: Include CSRF token
async function transferMoney(to: string, amount: number) {
  const csrfToken = getCsrfToken();
  await fetch('/api/transfer', {
    method: 'POST',
    headers: {
      'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify({ to, amount })
  });
}
Frontend Security Checklist:
  • No
    dangerouslySetInnerHTML
    with user input
  • No sensitive tokens in localStorage
  • No hardcoded API keys or secrets
  • CSRF protection for state-changing operations
  • Input validation on all form inputs
  • Output sanitization for user-generated content
  • HTTPS enforced (check in production)
  • No sensitive data in console.log
  • Proper authentication checks on protected routes
  • Secure password input (no autocomplete on sensitive fields)
识别性能瓶颈与优化机会:
typescript
// ❌ BAD: Unnecessary re-renders
function ProductList({ products }: { products: Product[] }) {
  const sortedProducts = products.sort((a, b) => b.price - a.price);
  // Re-sorts on every render!

  return (
    <div>
      {sortedProducts.map(p => (
        <ProductCard key={p.id} product={p} onUpdate={() => updateProduct(p.id)} />
      ))}
    </div>
  );
}

// ✅ GOOD: Memoized sorting and callbacks
function ProductList({ products }: { products: Product[] }) {
  const sortedProducts = useMemo(
    () => [...products].sort((a, b) => b.price - a.price),
    [products]
  );

  const handleUpdate = useCallback((id: string) => {
    updateProduct(id);
  }, []);

  return (
    <div>
      {sortedProducts.map(p => (
        <ProductCard key={p.id} product={p} onUpdate={() => handleUpdate(p.id)} />
      ))}
    </div>
  );
}

// ❌ BAD: No memoization for expensive child
function ExpensiveChild({ data }: { data: Data }) {
  // Complex rendering logic
  return <div>{/* ... */}</div>;
}

// ✅ GOOD: Memoized component
const ExpensiveChild = memo(function ExpensiveChild({ data }: { data: Data }) {
  // Complex rendering logic
  return <div>{/* ... */}</div>;
});

// ❌ BAD: Memory leak - no cleanup
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    // No cleanup!
  }, []);

  return <div>{count}</div>;
}

// ✅ GOOD: Proper cleanup
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>{count}</div>;
}

// ❌ BAD: No lazy loading for large components
import HeavyChart from './HeavyChart';
import HeavyEditor from './HeavyEditor';

// ✅ GOOD: Lazy loading
const HeavyChart = lazy(() => import('./HeavyChart'));
const HeavyEditor = lazy(() => import('./HeavyEditor'));

function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
      <HeavyEditor />
    </Suspense>
  );
}

// ❌ BAD: Inline object/function props
<Child
  config={{ theme: 'dark' }}
  onUpdate={() => doSomething()}
/>

// ✅ GOOD: Memoized props
const config = useMemo(() => ({ theme: 'dark' }), []);
const handleUpdate = useCallback(() => doSomething(), []);

<Child config={config} onUpdate={handleUpdate} />
React性能检查清单:
  • 对昂贵计算使用记忆化(useMemo)
  • 为子组件使用记忆化回调(useCallback)
  • 对昂贵子组件使用memo()
  • 在useEffect中正确清理(定时器、订阅)
  • 对大型组件使用懒加载
  • 对路由进行代码分割
  • 对长列表使用虚拟化(react-window)
  • 对频繁事件使用防抖(搜索、滚动)
  • 图片优化(next/image、懒加载)
  • 避免将内联对象/函数作为props
  • 正确使用key(唯一ID,而非索引)
  • 避免深层props透传(使用Context/Zustand)

3.2 React Performance Review

3.3 组件架构评审

Identify bottlenecks and optimization opportunities:
typescript
// ❌ BAD: Unnecessary re-renders
function ProductList({ products }: { products: Product[] }) {
  const sortedProducts = products.sort((a, b) => b.price - a.price);
  // Re-sorts on every render!

  return (
    <div>
      {sortedProducts.map(p => (
        <ProductCard key={p.id} product={p} onUpdate={() => updateProduct(p.id)} />
      ))}
    </div>
  );
}

// ✅ GOOD: Memoized sorting and callbacks
function ProductList({ products }: { products: Product[] }) {
  const sortedProducts = useMemo(
    () => [...products].sort((a, b) => b.price - a.price),
    [products]
  );

  const handleUpdate = useCallback((id: string) => {
    updateProduct(id);
  }, []);

  return (
    <div>
      {sortedProducts.map(p => (
        <ProductCard key={p.id} product={p} onUpdate={() => handleUpdate(p.id)} />
      ))}
    </div>
  );
}

// ❌ BAD: No memoization for expensive child
function ExpensiveChild({ data }: { data: Data }) {
  // Complex rendering logic
  return <div>{/* ... */}</div>;
}

// ✅ GOOD: Memoized component
const ExpensiveChild = memo(function ExpensiveChild({ data }: { data: Data }) {
  // Complex rendering logic
  return <div>{/* ... */}</div>;
});

// ❌ BAD: Memory leak - no cleanup
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    // No cleanup!
  }, []);

  return <div>{count}</div>;
}

// ✅ GOOD: Proper cleanup
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>{count}</div>;
}

// ❌ BAD: No lazy loading for large components
import HeavyChart from './HeavyChart';
import HeavyEditor from './HeavyEditor';

// ✅ GOOD: Lazy loading
const HeavyChart = lazy(() => import('./HeavyChart'));
const HeavyEditor = lazy(() => import('./HeavyEditor'));

function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
      <HeavyEditor />
    </Suspense>
  );
}

// ❌ BAD: Inline object/function props
<Child
  config={{ theme: 'dark' }}
  onUpdate={() => doSomething()}
/>

// ✅ GOOD: Memoized props
const config = useMemo(() => ({ theme: 'dark' }), []);
const handleUpdate = useCallback(() => doSomething(), []);

<Child config={config} onUpdate={handleUpdate} />
React Performance Checklist:
  • Memoization for expensive calculations (useMemo)
  • Memoized callbacks (useCallback) for child components
  • memo() for expensive child components
  • Proper cleanup in useEffect (intervals, subscriptions)
  • Lazy loading for heavy components
  • Code splitting for routes
  • Virtualization for long lists (react-window)
  • Debouncing for frequent events (search, scroll)
  • Image optimization (next/image, lazy loading)
  • No inline objects/functions as props
  • Proper key usage (unique IDs, not indexes)
  • Avoid deep prop drilling (use Context/Zustand)
检查关注点分离是否合理:
typescript
// ❌ BAD: Everything in one component
function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  // API call in component
  useEffect(() => {
    setLoading(true);
    fetch('/api/user')
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, []);

  // Business logic in component
  const fullName = user ? `${user.firstName} ${user.lastName}` : '';
  const isAdult = user?.age >= 18;

  // Validation in component
  const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{fullName}</div>;
}

// ✅ GOOD: Layered architecture
// api/userApi.ts (Data Access Layer)
export const userApi = {
  getUser: async (): Promise<User> => {
    const response = await fetch('/api/user');
    if (!response.ok) throw new Error('Failed to fetch user');
    return response.json();
  }
};

// hooks/useUser.ts (Business Logic Layer)
export function useUser() {
  const { data: user, isLoading, error } = useQuery({
    queryKey: ['user'],
    queryFn: userApi.getUser
  });

  const fullName = user ? `${user.firstName} ${user.lastName}` : '';
  const isAdult = user?.age >= 18;

  return { user, fullName, isAdult, isLoading, error };
}

// utils/validation.ts (Business Logic Layer)
export const emailSchema = z.string().email();

export function validateEmail(email: string): boolean {
  return emailSchema.safeParse(email).success;
}

// components/UserProfile.tsx (Presentation Layer)
export function UserProfile() {
  const { fullName, isLoading, error } = useUser();

  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;

  return <div className="text-lg font-semibold">{fullName}</div>;
}
架构检查清单:
  • 分层架构(展示层、业务逻辑层、数据访问层)
  • 不在组件中直接调用API
  • 不在组件中编写业务逻辑
  • 使用Hook封装可复用逻辑
  • 使用Zustand/Context管理全局状态
  • 使用React Query管理服务端状态
  • 无循环依赖
  • 遵循单一职责原则
  • 组件小巧且聚焦(少于200行)
  • 正确定义props类型(TypeScript接口)

3.3 Component Architecture Review

3.4 类型安全评审

Check for proper separation of concerns:
typescript
// ❌ BAD: Everything in one component
function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  // API call in component
  useEffect(() => {
    setLoading(true);
    fetch('/api/user')
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, []);

  // Business logic in component
  const fullName = user ? `${user.firstName} ${user.lastName}` : '';
  const isAdult = user?.age >= 18;

  // Validation in component
  const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{fullName}</div>;
}

// ✅ GOOD: Layered architecture
// api/userApi.ts (Data Access Layer)
export const userApi = {
  getUser: async (): Promise<User> => {
    const response = await fetch('/api/user');
    if (!response.ok) throw new Error('Failed to fetch user');
    return response.json();
  }
};

// hooks/useUser.ts (Business Logic Layer)
export function useUser() {
  const { data: user, isLoading, error } = useQuery({
    queryKey: ['user'],
    queryFn: userApi.getUser
  });

  const fullName = user ? `${user.firstName} ${user.lastName}` : '';
  const isAdult = user?.age >= 18;

  return { user, fullName, isAdult, isLoading, error };
}

// utils/validation.ts (Business Logic Layer)
export const emailSchema = z.string().email();

export function validateEmail(email: string): boolean {
  return emailSchema.safeParse(email).success;
}

// components/UserProfile.tsx (Presentation Layer)
export function UserProfile() {
  const { fullName, isLoading, error } = useUser();

  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;

  return <div className="text-lg font-semibold">{fullName}</div>;
}
Architecture Checklist:
  • Layered architecture (Presentation, Business Logic, Data Access)
  • No API calls directly in components
  • No business logic in components
  • Hooks for reusable logic
  • Zustand/Context for global state
  • React Query for server state
  • No circular dependencies
  • Single Responsibility Principle
  • Components are small and focused (<200 lines)
  • Proper prop types (TypeScript interfaces)
检查TypeScript使用是否规范:
typescript
// ❌ BAD: Using 'any'
function processData(data: any) {
  return data.value;
}

// ✅ GOOD: Proper types
interface ProcessData {
  value: string;
  count: number;
}

function processData(data: ProcessData): string {
  return data.value;
}

// ❌ BAD: Non-null assertion without justification
function getUser(users: User[], id: string) {
  return users.find(u => u.id === id)!.name; // Dangerous!
}

// ✅ GOOD: Proper null handling
function getUser(users: User[], id: string): string | null {
  return users.find(u => u.id === id)?.name ?? null;
}

// ❌ BAD: No runtime validation
function LoginForm() {
  const handleSubmit = (data: unknown) => {
    // Assuming data structure without validation
    login(data);
  };
}

// ✅ GOOD: Runtime validation with Zod
import { z } from 'zod';

const loginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});

type LoginData = z.infer<typeof loginSchema>;

function LoginForm() {
  const handleSubmit = (data: unknown) => {
    try {
      const validatedData = loginSchema.parse(data);
      login(validatedData); // Type-safe
    } catch (err) {
      // Handle validation errors
    }
  };
}

// ❌ BAD: Implicit any in event handlers
<input onChange={(e) => setValue(e.target.value)} />
// 'e' is implicitly 'any' in some configs

// ✅ GOOD: Explicit types
<input onChange={(e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value)} />

// ✅ BETTER: Typed handler
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setValue(e.target.value);
};

<input onChange={handleChange} />
类型安全检查清单:
  • 不使用'any'类型(除非确实必要)
  • 无正当理由不使用非空断言(!)
  • 正确定义props的接口/类型
  • 对外部数据使用Zod进行运行时验证
  • 对判别联合使用类型守卫
  • 为事件处理器显式定义类型
  • 在tsconfig.json中启用严格模式
  • 无隐式any类型
  • 在Hook中正确使用泛型

3.4 Type Safety Review

3.5 可访问性评审

Check for proper TypeScript usage:
typescript
// ❌ BAD: Using 'any'
function processData(data: any) {
  return data.value;
}

// ✅ GOOD: Proper types
interface ProcessData {
  value: string;
  count: number;
}

function processData(data: ProcessData): string {
  return data.value;
}

// ❌ BAD: Non-null assertion without justification
function getUser(users: User[], id: string) {
  return users.find(u => u.id === id)!.name; // Dangerous!
}

// ✅ GOOD: Proper null handling
function getUser(users: User[], id: string): string | null {
  return users.find(u => u.id === id)?.name ?? null;
}

// ❌ BAD: No runtime validation
function LoginForm() {
  const handleSubmit = (data: unknown) => {
    // Assuming data structure without validation
    login(data);
  };
}

// ✅ GOOD: Runtime validation with Zod
import { z } from 'zod';

const loginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});

type LoginData = z.infer<typeof loginSchema>;

function LoginForm() {
  const handleSubmit = (data: unknown) => {
    try {
      const validatedData = loginSchema.parse(data);
      login(validatedData); // Type-safe
    } catch (err) {
      // Handle validation errors
    }
  };
}

// ❌ BAD: Implicit any in event handlers
<input onChange={(e) => setValue(e.target.value)} />
// 'e' is implicitly 'any' in some configs

// ✅ GOOD: Explicit types
<input onChange={(e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value)} />

// ✅ BETTER: Typed handler
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setValue(e.target.value);
};

<input onChange={handleChange} />
Type Safety Checklist:
  • No 'any' types (except where truly necessary)
  • No non-null assertions (!) without justification
  • Proper interface/type definitions for props
  • Runtime validation with Zod for external data
  • Type guards for discriminated unions
  • Explicit types for event handlers
  • Strict mode enabled in tsconfig.json
  • No implicit any
  • Proper generic usage in hooks
检查是否符合WCAG 2.1 AA标准:
typescript
// ❌ BAD: No keyboard support, no ARIA labels
<div onClick={handleClick}>
  <input type="text" placeholder="Name" />
  <div className="text-red-500">Error message</div>
</div>

// ✅ GOOD: Semantic HTML, ARIA labels, keyboard support
<form onSubmit={handleSubmit}>
  <label htmlFor="name" className="block text-sm font-medium">
    Name
  </label>
  <input
    id="name"
    type="text"
    aria-label="Enter your name"
    aria-describedby="name-error"
    aria-invalid={hasError}
    className="mt-1 block w-full"
  />
  {hasError && (
    <p id="name-error" role="alert" className="text-red-500 text-sm">
      Error message
    </p>
  )}
  <button type="submit" className="mt-4 px-4 py-2 bg-blue-500">
    Submit
  </button>
</form>

// ❌ BAD: No alt text, poor color contrast
<div className="bg-gray-200 text-gray-300">
  <img src="/icon.png" />
  Click here
</div>

// ✅ GOOD: Alt text, proper contrast (WCAG AA)
<div className="bg-gray-900 text-white">
  <img src="/icon.png" alt="Settings icon" />
  <button className="text-lg font-medium">
    Open Settings
  </button>
</div>

// ❌ BAD: Custom select without keyboard navigation
function CustomSelect({ options }) {
  const [open, setOpen] = useState(false);

  return (
    <div onClick={() => setOpen(!open)}>
      {open && options.map(opt => (
        <div onClick={() => selectOption(opt)}>{opt}</div>
      ))}
    </div>
  );
}

// ✅ GOOD: Accessible custom select
function CustomSelect({ options }: { options: string[] }) {
  const [open, setOpen] = useState(false);
  const [selectedIndex, setSelectedIndex] = useState(0);

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'ArrowDown') {
      setSelectedIndex(i => Math.min(i + 1, options.length - 1));
    } else if (e.key === 'ArrowUp') {
      setSelectedIndex(i => Math.max(i - 1, 0));
    } else if (e.key === 'Enter') {
      selectOption(options[selectedIndex]);
    }
  };

  return (
    <div
      role="combobox"
      aria-expanded={open}
      aria-haspopup="listbox"
      tabIndex={0}
      onKeyDown={handleKeyDown}
      onClick={() => setOpen(!open)}
    >
      {open && (
        <ul role="listbox">
          {options.map((opt, index) => (
            <li
              key={opt}
              role="option"
              aria-selected={index === selectedIndex}
              onClick={() => selectOption(opt)}
            >
              {opt}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
可访问性检查清单:
  • 使用语义化HTML元素(button、nav、main等)
  • 为交互元素添加ARIA标签
  • 支持键盘导航(Tab、Enter、方向键)
  • 焦点管理(可见的焦点状态)
  • 颜色对比度符合WCAG AA标准(文本为4.5:1)
  • 所有图片均有替代文本
  • 表单标签正确关联(htmlFor)
  • 错误消息使用role="alert"
  • 无键盘陷阱
  • 提供主内容跳转链接
  • 标题按逻辑顺序排列(h1、h2、h3)
  • 交互元素具备正确的role属性

3.5 Accessibility Review

3.6 响应式设计评审

Check WCAG 2.1 AA compliance:
typescript
// ❌ BAD: No keyboard support, no ARIA labels
<div onClick={handleClick}>
  <input type="text" placeholder="Name" />
  <div className="text-red-500">Error message</div>
</div>

// ✅ GOOD: Semantic HTML, ARIA labels, keyboard support
<form onSubmit={handleSubmit}>
  <label htmlFor="name" className="block text-sm font-medium">
    Name
  </label>
  <input
    id="name"
    type="text"
    aria-label="Enter your name"
    aria-describedby="name-error"
    aria-invalid={hasError}
    className="mt-1 block w-full"
  />
  {hasError && (
    <p id="name-error" role="alert" className="text-red-500 text-sm">
      Error message
    </p>
  )}
  <button type="submit" className="mt-4 px-4 py-2 bg-blue-500">
    Submit
  </button>
</form>

// ❌ BAD: No alt text, poor color contrast
<div className="bg-gray-200 text-gray-300">
  <img src="/icon.png" />
  Click here
</div>

// ✅ GOOD: Alt text, proper contrast (WCAG AA)
<div className="bg-gray-900 text-white">
  <img src="/icon.png" alt="Settings icon" />
  <button className="text-lg font-medium">
    Open Settings
  </button>
</div>

// ❌ BAD: Custom select without keyboard navigation
function CustomSelect({ options }) {
  const [open, setOpen] = useState(false);

  return (
    <div onClick={() => setOpen(!open)}>
      {open && options.map(opt => (
        <div onClick={() => selectOption(opt)}>{opt}</div>
      ))}
    </div>
  );
}

// ✅ GOOD: Accessible custom select
function CustomSelect({ options }: { options: string[] }) {
  const [open, setOpen] = useState(false);
  const [selectedIndex, setSelectedIndex] = useState(0);

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'ArrowDown') {
      setSelectedIndex(i => Math.min(i + 1, options.length - 1));
    } else if (e.key === 'ArrowUp') {
      setSelectedIndex(i => Math.max(i - 1, 0));
    } else if (e.key === 'Enter') {
      selectOption(options[selectedIndex]);
    }
  };

  return (
    <div
      role="combobox"
      aria-expanded={open}
      aria-haspopup="listbox"
      tabIndex={0}
      onKeyDown={handleKeyDown}
      onClick={() => setOpen(!open)}
    >
      {open && (
        <ul role="listbox">
          {options.map((opt, index) => (
            <li
              key={opt}
              role="option"
              aria-selected={index === selectedIndex}
              onClick={() => selectOption(opt)}
            >
              {opt}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
Accessibility Checklist:
  • Semantic HTML elements (button, nav, main, etc.)
  • ARIA labels for interactive elements
  • Keyboard navigation support (Tab, Enter, Arrows)
  • Focus management (visible focus states)
  • Color contrast meets WCAG AA (4.5:1 for text)
  • Alt text for all images
  • Form labels properly associated (htmlFor)
  • Error messages use role="alert"
  • No keyboard traps
  • Skip links for main content
  • Headings in logical order (h1, h2, h3)
  • Interactive elements have proper roles
检查Tailwind/响应式模式是否规范:
typescript
// ❌ BAD: Fixed widths, no responsive classes
<div className="w-800 h-600">
  <img src="/hero.jpg" className="w-full" />
</div>

// ✅ GOOD: Responsive Tailwind classes
<div className="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  <img
    src="/hero.jpg"
    alt="Hero"
    className="w-full h-auto object-cover md:h-96 lg:h-[500px]"
  />
</div>

// ❌ BAD: No mobile considerations
<div className="flex gap-8">
  <Sidebar />
  <MainContent />
</div>

// ✅ GOOD: Mobile-first responsive layout
<div className="flex flex-col lg:flex-row gap-4 lg:gap-8">
  <aside className="w-full lg:w-64">
    <Sidebar />
  </aside>
  <main className="flex-1">
    <MainContent />
  </main>
</div>

// ❌ BAD: Fixed font sizes
<h1 className="text-32">Title</h1>

// ✅ GOOD: Responsive typography
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
  Title
</h1>
响应式设计检查清单:
  • 采用移动优先的设计思路(基础样式适配移动端)
  • 使用正确的断点(sm、md、lg、xl、2xl)
  • 使用灵活布局(flex、grid)
  • 响应式图片(w-full h-auto、object-fit)
  • 响应式排版(响应式文本大小)
  • 触控友好的点击区域(最小44x44px)
  • 移动端无横向滚动
  • 在多种屏幕尺寸上测试

3.6 Responsive Design Review

3.7 代码质量评审

Check Tailwind/responsive patterns:
typescript
// ❌ BAD: Fixed widths, no responsive classes
<div className="w-800 h-600">
  <img src="/hero.jpg" className="w-full" />
</div>

// ✅ GOOD: Responsive Tailwind classes
<div className="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  <img
    src="/hero.jpg"
    alt="Hero"
    className="w-full h-auto object-cover md:h-96 lg:h-[500px]"
  />
</div>

// ❌ BAD: No mobile considerations
<div className="flex gap-8">
  <Sidebar />
  <MainContent />
</div>

// ✅ GOOD: Mobile-first responsive layout
<div className="flex flex-col lg:flex-row gap-4 lg:gap-8">
  <aside className="w-full lg:w-64">
    <Sidebar />
  </aside>
  <main className="flex-1">
    <MainContent />
  </main>
</div>

// ❌ BAD: Fixed font sizes
<h1 className="text-32">Title</h1>

// ✅ GOOD: Responsive typography
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
  Title
</h1>
Responsive Design Checklist:
  • Mobile-first approach (base styles for mobile)
  • Proper breakpoints (sm, md, lg, xl, 2xl)
  • Flexible layouts (flex, grid)
  • Responsive images (w-full h-auto, object-fit)
  • Responsive typography (responsive text sizes)
  • Touch-friendly hit areas (min 44x44px)
  • No horizontal scrolling on mobile
  • Tested on multiple screen sizes
评估代码的可读性与可维护性:
typescript
// ❌ BAD: Unclear names, deeply nested
function p(d) {
  if (d) {
    if (d.u) {
      if (d.u.n) {
        if (d.u.n.length > 0) {
          return d.u.n;
        }
      }
    }
  }
  return 'Anonymous';
}

// ✅ GOOD: Clear names, early returns
function getUserName(data: UserData | null): string {
  if (!data?.user?.name) return 'Anonymous';
  if (data.user.name.length === 0) return 'Anonymous';

  return data.user.name;
}

// ✅ BETTER: Optional chaining
function getUserName(data: UserData | null): string {
  return data?.user?.name || 'Anonymous';
}

// ❌ BAD: Magic numbers and strings
if (user.age > 18 && status === 'active') {
  grantAccess();
}

// ✅ GOOD: Named constants
const MINIMUM_AGE = 18;
const USER_STATUS = {
  ACTIVE: 'active',
  INACTIVE: 'inactive'
} as const;

if (user.age > MINIMUM_AGE && status === USER_STATUS.ACTIVE) {
  grantAccess();
}

// ❌ BAD: Long component with multiple responsibilities
function UserDashboard() {
  // 300 lines of code handling:
  // - User data fetching
  // - Analytics tracking
  // - Notification handling
  // - UI rendering
}

// ✅ GOOD: Split into focused components
function UserDashboard() {
  return (
    <div>
      <UserProfile />
      <UserAnalytics />
      <UserNotifications />
    </div>
  );
}
代码质量检查清单:
  • 使用清晰、描述性的命名(如getUserName,而非gn)
  • 不使用魔法数字或字符串(使用常量)
  • 使用提前返回而非深层嵌套
  • 小巧的函数/组件(少于100行)
  • 遵循单一职责原则
  • 遵循DRY原则(避免重复代码)
  • 无注释掉的代码
  • 生产代码中无console.log
  • 代码风格一致
  • 正确的错误处理

3.7 Code Quality Review

3.8 React Hooks最佳实践

Evaluate readability and maintainability:
typescript
// ❌ BAD: Unclear names, deeply nested
function p(d) {
  if (d) {
    if (d.u) {
      if (d.u.n) {
        if (d.u.n.length > 0) {
          return d.u.n;
        }
      }
    }
  }
  return 'Anonymous';
}

// ✅ GOOD: Clear names, early returns
function getUserName(data: UserData | null): string {
  if (!data?.user?.name) return 'Anonymous';
  if (data.user.name.length === 0) return 'Anonymous';

  return data.user.name;
}

// ✅ BETTER: Optional chaining
function getUserName(data: UserData | null): string {
  return data?.user?.name || 'Anonymous';
}

// ❌ BAD: Magic numbers and strings
if (user.age > 18 && status === 'active') {
  grantAccess();
}

// ✅ GOOD: Named constants
const MINIMUM_AGE = 18;
const USER_STATUS = {
  ACTIVE: 'active',
  INACTIVE: 'inactive'
} as const;

if (user.age > MINIMUM_AGE && status === USER_STATUS.ACTIVE) {
  grantAccess();
}

// ❌ BAD: Long component with multiple responsibilities
function UserDashboard() {
  // 300 lines of code handling:
  // - User data fetching
  // - Analytics tracking
  // - Notification handling
  // - UI rendering
}

// ✅ GOOD: Split into focused components
function UserDashboard() {
  return (
    <div>
      <UserProfile />
      <UserAnalytics />
      <UserNotifications />
    </div>
  );
}
Code Quality Checklist:
  • Clear, descriptive names (getUserName, not gn)
  • No magic numbers or strings (use constants)
  • Early returns instead of deep nesting
  • Small functions/components (<100 lines)
  • Single Responsibility Principle
  • DRY (Don't Repeat Yourself)
  • No commented-out code
  • No console.log in production code
  • Consistent code style
  • Proper error handling
typescript
// ❌ BAD: Missing dependencies
useEffect(() => {
  fetchData(userId, filter);
}, []); // userId and filter are missing!

// ✅ GOOD: All dependencies included
useEffect(() => {
  fetchData(userId, filter);
}, [userId, filter]);

// ❌ BAD: Object dependency (recreated every render)
const options = { sort: 'asc', limit: 10 };

useEffect(() => {
  fetchData(options);
}, [options]); // Will run every render!

// ✅ GOOD: Memoized object
const options = useMemo(() => ({
  sort: 'asc',
  limit: 10
}), []);

useEffect(() => {
  fetchData(options);
}, [options]);

// ❌ BAD: Stale closure
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1); // Uses stale count!
    }, 1000);

    return () => clearInterval(interval);
  }, []); // Empty deps, count is stale

  return <div>{count}</div>;
}

// ✅ GOOD: Functional update
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1); // Uses current count
    }, 1000);

    return () => clearInterval(interval);
  }, []); // Empty deps OK now

  return <div>{count}</div>;
}

3.8 React Hooks Best Practices

步骤4:提供结构化反馈

typescript
// ❌ BAD: Missing dependencies
useEffect(() => {
  fetchData(userId, filter);
}, []); // userId and filter are missing!

// ✅ GOOD: All dependencies included
useEffect(() => {
  fetchData(userId, filter);
}, [userId, filter]);

// ❌ BAD: Object dependency (recreated every render)
const options = { sort: 'asc', limit: 10 };

useEffect(() => {
  fetchData(options);
}, [options]); // Will run every render!

// ✅ GOOD: Memoized object
const options = useMemo(() => ({
  sort: 'asc',
  limit: 10
}), []);

useEffect(() => {
  fetchData(options);
}, [options]);

// ❌ BAD: Stale closure
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1); // Uses stale count!
    }, 1000);

    return () => clearInterval(interval);
  }, []); // Empty deps, count is stale

  return <div>{count}</div>;
}

// ✅ GOOD: Functional update
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(c => c + 1); // Uses current count
    }, 1000);

    return () => clearInterval(interval);
  }, []); // Empty deps OK now

  return <div>{count}</div>;
}
清晰格式化评审结果:
markdown
undefined

Step 4: Provide Structured Feedback

Code Review: [Component/Feature Name]

Summary

Format review results clearly:
markdown
undefined
[Brief overall assessment: Excellent/Good/Needs Improvement/Critical Issues]

Code Review: [Component/Feature Name]

Critical Issues 🚨

Summary

[Brief overall assessment: Excellent/Good/Needs Improvement/Critical Issues]
  1. [Issue Title] - [file:line]
    • Problem: [Description]
    • Impact: [Security/Performance/Accessibility]
    • Fix:
    typescript
    // Suggested fix

Critical Issues 🚨

High Priority ⚠️

  1. [Issue Title] - [file:line]
    • Problem: [Description]
    • Impact: [Security/Performance/Accessibility]
    • Fix:
    typescript
    // Suggested fix
[Same format]

High Priority ⚠️

Medium Priority ⚡

[Same format]
[Same format]

Medium Priority ⚡

Low Priority 💡

[Same format]
[Same format]

Low Priority 💡

What's Good ✅

[Same format]
  • [Highlight positive aspects]
  • [Good practices used]

What's Good ✅

Recommendations

  • [Highlight positive aspects]
  • [Good practices used]
  1. [Actionable improvement]
  2. [Actionable improvement]

Recommendations

Overall Score

  1. [Actionable improvement]
  2. [Actionable improvement]
  • Security: 8/10
  • Performance: 7/10
  • Code Quality: 9/10
  • Accessibility: 6/10
  • Type Safety: 8/10
Overall: 7.6/10
undefined

Overall Score

与其他技能的集成

与feature-builder集成

  • Security: 8/10
  • Performance: 7/10
  • Code Quality: 9/10
  • Accessibility: 6/10
  • Type Safety: 8/10
Overall: 7.6/10
undefined
  • 评审完整功能(UI + 业务逻辑 + API)
  • 确保分层架构正确实现

Integration with Other Skills

与react-component-generator集成

With feature-builder

  • Review complete features (UI + business logic + API)
  • Ensure layered architecture is properly implemented
  • 评审生成的组件
  • 检查模板使用与定制情况

With react-component-generator

与ui-analyzer集成

  • Review generated components
  • Check template usage and customization
  • 评审从设计截图生成的UI代码
  • 验证响应式设计实现

With ui-analyzer

最佳实践

  • Review UI code generated from design screenshots
  • Verify responsive design implementation
  1. 建设性反馈: 始终提供带有代码示例的可执行修复方案
  2. 优先级排序: 优先关注严重问题(安全、可访问性)
  3. 解释原因: 帮助用户理解问题的影响与背后的逻辑
  4. 展示前后对比: 提供清晰的代码示例
  5. 具体明确: 引用具体的行号与文件
  6. 平衡反馈: 同时突出代码的优点
  7. 贴合实际: 考虑项目约束与截止日期
  8. 传递知识: 必要时讲解React/前端相关概念

Best Practices

严重等级

  1. Be Constructive: Always provide actionable fixes with code examples
  2. Prioritize: Focus on critical issues (security, accessibility) first
  3. Explain Why: Help user understand the reasoning and impact
  4. Show Before/After: Provide clear code examples
  5. Be Specific: Reference exact lines and files
  6. Balance: Highlight what's good too
  7. Be Practical: Consider project constraints and deadlines
  8. Educate: Explain React/frontend concepts when needed
  • 🚨 严重: 安全漏洞(XSS、CSRF)、数据泄露、程序崩溃
  • ⚠️ 高优先级: 性能问题(内存泄漏)、可访问性违规、用户体验损坏
  • 中优先级: 代码质量、可维护性、缺失TypeScript类型
  • 💡 低优先级: 代码风格、文档、次要优化

Severity Levels

参考文件

  • 🚨 CRITICAL: Security vulnerabilities (XSS, CSRF), data exposure, crashes
  • ⚠️ HIGH: Performance issues (memory leaks), accessibility violations, broken UX
  • MEDIUM: Code quality, maintainability, missing TypeScript types
  • 💡 LOW: Code style, documentation, minor optimizations
  • references/frontend-security.md
    - 前端安全最佳实践
  • references/react-patterns.md
    - React模式与反模式
  • references/accessibility-guide.md
    - WCAG合规指南
本技能可实现全面、专业的前端代码评审,提升代码质量、安全性与用户体验!

Reference Files

  • references/frontend-security.md
    - Frontend security best practices
  • references/react-patterns.md
    - React patterns and anti-patterns
  • references/accessibility-guide.md
    - WCAG compliance guide
This skill enables thorough, professional frontend code reviews that improve code quality, security, and user experience!