关于 react-code-review
面向 React 开发者的结构化代码审查技能,适用于合并前检查或重构后评估。报告按严重程度分类的问题、正向发现及附带示例的优先建议。
主要功能
- 01检查 React 组件与 Hooks
- 02审查 React 19 模式
- 03检查无障碍和 TypeScript
- 04分析架构与性能
- 05按严重程度整理发现与建议
适用场景
- 01合并前审查 React 改动
- 02检查交互组件的无障碍性
- 03发现 Hooks 依赖或清理问题
- 04评估状态管理和性能方案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill react-code-review安装后在 Claude Code 中输入/react-code-review确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/accessibility.mdcomponent-architecture.mdhooks-patterns.md详细介绍
React 代码审查
概述
此技能为 React 应用提供结构化、全面的代码审查。它会根据 React 19 最佳实践、组件架构模式、Hook 用法、无障碍标准和生产就绪标准评估代码。审查会生成可执行的发现,按严重程度分类(严重、警告、建议),并提供具体的改进代码示例。
通过 Agent 系统调用时,此技能会将深入的架构分析委托给 react-software-architect-review Agent。
适用场景
- 合并前审查 React 组件、Hook 和页面
- 验证组件组合与可复用模式
- 检查 Hook 的正确用法(useState、useEffect、useMemo、useCallback)
- 审查 React 19 模式(use、useOptimistic、useFormStatus、Actions)
- 评估状态管理方案(本地状态、Context、外部存储)
- 评估性能优化(记忆化、代码拆分、延迟加载)
- 审查无障碍合规性(WCAG、语义化 HTML、ARIA)
- 验证 Props、状态和事件的 TypeScript 类型
- 检查 Tailwind CSS 和样式模式
- 实现新的 React 功能或重构组件架构后
说明
-
确定范围:确定要审查哪些 React 组件和 Hook。使用
glob查找.tsx/.jsx文件,并使用grep查找组件定义、Hook 用法和 Context 提供者。 -
分析组件架构:验证组件组合是否合理——检查是否遵循单一职责、大小是否合适,以及是否可复用。查找过大的组件(>200 行)、Props 过多的组件(>7 个)或职责混杂的组件。
-
审查 Hook 用法:验证 Hook 用法是否正确——检查
useEffect/useMemo/useCallback的依赖数组,验证useEffect中的清理函数,并找出因缺少或错误的记忆化而导致的不必要重新渲染。 -
评估状态管理:评估状态的存放位置——检查状态是否恰当地就近管理、是否进行了不必要的状态提升,以及 Context 与外部存储的使用是否合适。验证服务端状态是否使用 TanStack Query、SWR 或类似库,而非手动采用
useEffect+useState模式。 -
检查无障碍性:审查语义化 HTML 的使用、ARIA 属性、键盘导航、焦点管理和屏幕阅读器兼容性。验证交互元素是否具备无障碍性,以及表单输入是否有适当的标签。
-
评估性能:查找不必要的重新渲染、昂贵组件是否缺少
React.memo、useCallback/useMemo使用是否不当、是否缺少代码拆分,以及是否导入了过大的包。 -
审查 TypeScript 集成:检查 Props 类型定义、事件处理器类型、泛型组件模式,以及工具类型的正确用法。验证在可以使用具体类型时是否避免使用
any。 -
生成审查报告:生成结构化报告,包含按严重程度分类的发现(严重、警告、建议)、正面观察,以及附有代码示例的优先级建议。
示例
示例 1:Hook 依赖项问题
// ❌ Bad: Missing dependency causes stale closure
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, []); // Missing userId in dependency array
return <div>{user?.name}</div>;
}
// ✅ Good: Proper dependencies with cleanup
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
let cancelled = false;
fetchUser(userId).then((data) => {
if (!cancelled) setUser(data);
});
return () => { cancelled = true; };
}, [userId]);
return <div>{user?.name}</div>;
}
// ✅ Better: Use TanStack Query for server state
function UserProfile({ userId }: { userId: string }) {
const { data: user, isLoading } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
});
if (isLoading) return <Skeleton />;
return <div>{user?.name}</div>;
}
示例 2:组件组合
// ❌ Bad: Monolithic component mixing data fetching, filtering, and rendering
function Dashboard() {
const [users, setUsers] = useState([]);
const [filter, setFilter] = useState('');
useEffect(() => { /* fetch + filter + sort all in one */ }, [filter]);
return <div>{/* 200+ lines of mixed concerns */}</div>;
}
// ✅ Good: Composed from focused components with custom hooks
function Dashboard() {
return (
<div>
<UserFilters />
<Suspense fallback={<TableSkeleton />}>
<UserTable />
</Suspense>
<UserPagination />
</div>
);
}
示例 3:无障碍审查
// ❌ Bad: Inaccessible interactive elements
function Menu({ items }: { items: MenuItem[] }) {
const [open, setOpen] = useState(false);
return (
<div>
<div onClick={() => setOpen(!open)}>Menu</div>
{open && (
<div>
{items.map(item => (
<div key={item.id} onClick={() => navigate(item.path)}>
{item.label}
</div>
))}
</div>
)}
</div>
);
}
// ✅ Good: Accessible with proper semantics and keyboard support
function Menu({ items }: { items: MenuItem[] }) {
const [open, setOpen] = useState(false);
return (
<nav aria-label="Main navigation">
<button
onClick={() => setOpen(!open)}
aria-expanded={open}
aria-controls="menu-list"
>
Menu
</button>
{open && (
<ul id="menu-list" role="menu">
{items.map(item => (
<li key={item.id} role="menuitem">
<a href={item.path}>{item.label}</a>
</li>
))}
</ul>
)}
</nav>
);
}
示例 4:性能优化
// ❌ Bad: Unstable callback recreated every render causes child re-renders
{filtered.map(product => (
<ProductCard
key={product.id}
product={product}
onSelect={() => console.log(product.id)} // New function each render
/>
))}
// ✅ Good: Stable callback + memoized child
const handleSelect = useCallback((id: string) => {
console.log(id);
}, []);
const filtered = useMemo(
() => products.filter(p => p.name.toLowerCase().includes(search.toLowerCase())),
[products, search]
);
{filtered.map(product => (
<ProductCard key={product.id} product={product} onSelect={handleSelect} />
))}
const ProductCard = memo(function ProductCard({ product, onSelect }: Props) {
return <div onClick={() => onSelect(product.id)}>{product.name}</div>;
});
示例 5:TypeScript Props 审查
// ❌ Bad: Loose typing and missing prop definitions
function Card({ data, onClick, children, ...rest }: any) {
return (
<div onClick={onClick} {...rest}>
<h2>{data.title}</h2>
{children}
</div>
);
}
// ✅ Good: Strict typing with proper interfaces
interface CardProps extends React.ComponentPropsWithoutRef<'article'> {
title: string;
description?: string;
variant?: 'default' | 'outlined' | 'elevated';
onAction?: (event: React.MouseEvent<HTMLButtonElement>) => void;
children: React.ReactNode;
}
function Card({
title,
description,
variant = 'default',
onAction,
children,
className,
...rest
}: CardProps) {
return (
<article className={cn('card', `card--${variant}`, className)} {...rest}>
<h2>{title}</h2>
{description && <p>{description}</p>}
{children}
{onAction && <button onClick={onAction}>Action</button>}
</article>
);
}
审查输出格式
按以下格式整理所有代码审查发现:
1. 摘要
简要概述整体质量评分(1-10)和关键观察。
2. 严重问题(必须修复)
会导致 Bug、安全漏洞或功能失效的问题。
3. 警告(应当修复)
违反最佳实践、导致性能问题或降低可维护性的问题。
4. 建议(可考虑改进)
在代码组织、无障碍性或开发者体验方面的改进。
5. 正面观察
值得肯定的良好实现模式和实践。
6. 建议
按优先级列出后续步骤,并提供代码示例,帮助实现影响最大的改进。
最佳实践
- 保持组件职责单一,控制在 200 行以内
- 将状态与使用它的组件放在一起
- 使用自定义 Hook 从组件中提取可复用逻辑
- 只有在测量确认重新渲染成本值得优化时,才使用
React.memo - 使用 TanStack Query 或 SWR 管理服务端状态,而不是使用
useEffect+useState - 通过
useEffect订阅外部资源时,务必包含清理函数 - 优先编写语义化 HTML,仅在原生语义不足时添加 ARIA
- 启用 TypeScript 严格模式,并避免在组件属性中使用
any - 实现错误边界,以便在发生故障时优雅处理
- 优先使用组合,避免条件渲染过于复杂
限制和警告
- 遵循项目的 React 版本——不要为较旧版本建议使用 React 19 的特性
- 除非项目已统一采用某个状态管理库,否则不要强制指定特定库
- 记忆化并非总有益——只有在重新渲染的影响可以测量时才建议使用
- 无障碍建议应以 WCAG 2.1 AA 为基准
- 聚焦于高置信度问题,避免对主观风格选择误报
- 除非有明确且可衡量的收益,否则不要建议重写正常工作的组件
参考资料
详细的审查清单和模式文档请参阅 references/ 目录:
references/hooks-patterns.md— React Hook 最佳实践和常见错误references/component-architecture.md— 组件组合和设计模式references/accessibility.md— React 无障碍检查清单和 ARIA 模式