React Doctor 深度解析:当 AI 写的 React 代码比人类还烂,谁来当"主治医师"?
一、一个尴尬的现实:AI 编程助手正在制造技术债
2026年,AI 编程助手已经渗透到几乎每个开发者的日常工作流中。Claude Code、Cursor、Copilot、Codex……它们能快速生成组件、编写 Hook、搭建页面。但一个越来越明显的问题被忽视了:AI 写的 React 代码质量,可能比初级开发者还差。
先看几个 AI 编程助手"经典处方":
// AI 生成的"经典"反模式 #1:在 Effect 中同步派生状态
function SearchPage({ query }: { query: string }) {
const [filteredResults, setFilteredResults] = useState([]);
useEffect(() => {
// 不必要的 Effect + 不必要的状态
const results = data.filter(item => item.name.includes(query));
setFilteredResults(results);
}, [query]);
return <List items={filteredResults} />;
}
// 正确写法:直接计算,无需 Effect
function SearchPage({ query }: { query: string }) {
const filteredResults = data.filter(item => item.name.includes(query));
return <List items={filteredResults} />;
}
// AI 生成的"经典"反模式 #2:级联 setState
function Dashboard({ value }: { value: string }) {
const [a, setA] = useState('');
const [b, setB] = useState('');
useEffect(() => {
setA(value); // 触发额外渲染
setB(value); // 又触发额外渲染
}, [value]);
}
// AI 生成的"经典"反模式 #3:数组索引作为 key
{items.map((item, index) => (
<ListItem key={index} data={item} /> // 列表变化时导致错乱
))}
这些反模式不是个例——它们是 AI 编程助手的"默认处方"。因为 AI 模型训练数据中充满了这些写法,它们自然倾向生成类似代码。
问题核心:谁来做 AI 代码的"质检员"?
React Doctor 就是为此而生的。它由 Million.js 团队(aidenybai)开发,GitHub 7.6K+ Stars,一句话定位:"Your agent writes bad React. This catches it."
二、React Doctor 核心架构:6 大诊断模块
2.1 架构总览
┌──────────────────────────────────────────────────────────┐
│ React Doctor │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ State & │ │ Performance │ │ Architecture │ │
│ │ Effects 检测 │ │ 检测 │ │ 检测 │ │
│ └──────┬──────┘ └──────┬───────┘ └───────┬────────┘ │
│ │ │ │ │
│ ┌──────┴──────┐ ┌──────┴───────┐ ┌───────┴────────┐ │
│ │ Security │ │ Accessibility│ │ Dead Code │ │
│ │ 检测 │ │ 检测 │ │ 检测 │ │
│ └──────┬──────┘ └──────┬───────┘ └───────┬────────┘ │
│ │ │ │ │
│ └────────────────┼───────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 评分引擎(0-100 健康分) │ │
│ │ 75+ Great │ 50-74 Needs Work │ <50 Critical │ │
│ └───────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
2.2 六大诊断模块详解
| 模块 | 检测范围 | 典型规则数 | 严重程度 |
|---|---|---|---|
| State & Effects | 不必要的 Effect、派生状态、级联 setState、Effect 依赖错误 | 15+ | Error |
| Performance | 不必要的重渲染、大组件拆分、memo 滥用/缺失 | 12+ | Warning |
| Architecture | 组件职责、Hook 规则、prop drilling | 10+ | Warning |
| Security | dangerouslySetInnerHTML、XSS 风险、敏感数据暴露 | 8+ | Error |
| Accessibility | 语义化标签、ARIA 属性、键盘导航 | 10+ | Warning |
| Dead Code | 未使用的导出、重复类型定义、冗余文件 | 15+ | Info |
2.3 评分算法
React Doctor 的评分不是简单的"扣分制",而是一个加权评分系统:
// 评分算法核心逻辑(简化版)
function calculateScore(diagnostics: Diagnostic[]): number {
const weights = {
error: 10, // 每个错误扣 10 分
warning: 3, // 每个警告扣 3 分
info: 1, // 每个提示扣 1 分
};
let deductions = 0;
for (const d of diagnostics) {
deductions += weights[d.severity];
}
// 基础分 100,扣到 0 为止
return Math.max(0, 100 - deductions);
}
实际评分会更复杂——考虑了项目规模归一化(大项目不应天然低分)和规则权重差异。但核心思路是:每一条诊断都有明确的影响,扣分透明可追溯。
三、60+ Lint 规则:覆盖你没想到的每一个坑
3.1 核心 Lint 规则分类
React Doctor 内置了 60+ 条专业 Lint 规则,远超 ESLint 默认的 React 插件。以下是按类别整理的关键规则:
State & Effects(状态与副作用)
| 规则 ID | 检测内容 | 为什么重要 |
|---|---|---|
no-derived-useState | 从 props 派生的 useState | 导致状态不同步、多余渲染 |
no-cascading-setState | Effect 中连续多次 setState | 每次 setState 触发额外渲染 |
no-render-in-render | 渲染期间触发状态更新 | 无限循环风险 |
rerender-state-only-in-handlers | 非事件处理中更新状态 | 违反单向数据流 |
no-chain-state-updates | 连锁的状态更新 | 竞态条件 |
no-unnecessary-effect | 可用 useMemo/直接计算替代的 Effect | 性能浪费 |
no-effect-with-cleanup-only | 只有清理函数没有副作用的 Effect | 代码噪声 |
Performance(性能)
| 规则 ID | 检测内容 | 为什么重要 |
|---|---|---|
no-array-index-as-key | 使用数组索引作为 key | 列表更新错乱 |
no-inline-function-as-prop | 内联函数作为 prop | 每次渲染创建新引用,子组件不必要重渲染 |
no-object-as-prop | 内联对象作为 prop | 同上 |
prefer-memo-for-expensive | 昂贵计算缺少 memo | 性能瓶颈 |
no-memo-on-primitive | 原始值不必要的 memo | 过度优化 |
Security(安全)
| 规则 ID | 检测内容 | 为什么重要 |
|---|---|---|
react/no-danger | dangerouslySetInnerHTML | XSS 攻击向量 |
no-eval-in-effect | Effect 中动态执行代码 | 代码注入 |
no-expose-sensitive-props | 敏感数据通过 props 传递 | 数据泄露 |
3.2 规则自动切换:框架感知
React Doctor 最聪明的设计之一是规则自动切换——它根据检测到的框架和 React 版本动态启用/禁用规则:
// 框架检测与规则切换逻辑(简化版)
function detectFramework(project: Project): RuleSet {
const rules: RuleSet = baseRules;
// Next.js 特定规则
if (project.framework === 'next.js') {
rules.enable('next/no-img-element'); // 禁用 <img>,用 <Image>
rules.enable('next/no-html-link-for-pages'); // 禁用 <a>,用 <Link>
rules.enable('no-server-components-state'); // Server Components 无状态
}
// Vite 特定规则
if (project.framework === 'vite') {
rules.enable('no-process-env'); // Vite 用 import.meta.env
}
// React Native 特定规则
if (project.framework === 'react-native') {
rules.enable('rn-no-raw-text'); // 文本必须包在 <Text> 中
rules.disable('no-object-as-prop'); // RN 中 style 对象是正常的
}
// React 19+ 特定规则
if (project.reactVersion >= 19) {
rules.enable('no-ref-callback'); // React 19 支持 ref 作为 prop
rules.enable('no-forward-ref'); // forwardRef 不再需要
}
// React Compiler 检测
if (project.hasReactCompiler) {
rules.enable('react-hooks-js/*'); // 启用编译器正确性规则
}
return rules;
}
这意味着你不需要手动配置——React Doctor 自动适应你的项目环境。
四、AI Agent 集成:让 AI 编程助手"学会"写好代码
这是 React Doctor 最具前瞻性的功能。传统 Lint 工具只能"事后发现问题",React Doctor 直接把最佳实践注入到 AI 编程助手的知识库中。
4.1 一键安装 Agent 规则
npx -y react-doctor@latest install
执行后,React Doctor 会:
- 扫描项目:检测你使用的 AI 编程工具
- 生成规则文件:针对每个 Agent 生成对应的规则文件
- 自动注入:将规则写入 Agent 的配置目录
Detected agents:
✓ Claude Code → .claude/CLAUDE.md
✓ Cursor → .cursor/rules/react-doctor.mdc
✓ Codex → AGENTS.md
✓ OpenCode → .opencode/rules.md
Install rules for all? [Y/n]
4.2 注入的规则内容示例
以 Claude Code 为例,React Doctor 会在 CLAUDE.md 中追加:
## React Best Practices (via React Doctor)
### State & Effects
- NEVER use useState for derived values. Compute directly: `const filtered = data.filter(...)`
- NEVER chain setState in useEffect. Use a single update or batch with flushSync
- NEVER use useEffect for syncing state with props. Just use the prop directly
- PREFER event handlers for state updates, not effects
### Performance
- NEVER use array index as key in .map(). Use a stable unique identifier
- AVOID inline objects/functions as props — extract to constants or useMemo
- USE React.memo only for components with expensive renders, not for primitives
### Security
- NEVER use dangerouslySetInnerHTML without sanitization
- AVOID eval() or Function() constructor in effects
### Architecture
- KEEP components under 200 lines. Extract sub-components
- LIMIT prop count to 5. Group related props into objects
4.3 支持 50+ AI 编程工具
React Doctor 的 Agent 集成支持当前主流的所有 AI 编程工具:
| 工具 | 规则文件位置 | 支持版本 |
|---|---|---|
| Claude Code | .claude/CLAUDE.md | 最新 |
| Cursor | .cursor/rules/*.mdc | 0.45+ |
| Codex | AGENTS.md | 最新 |
| OpenCode | .opencode/rules.md | 最新 |
| Cline | .clinerules | 最新 |
| GitHub Copilot | .github/copilot-instructions.md | 最新 |
| Continue | .continue/rules.md | 最新 |
| Aider | .aider.conf.yml | 最新 |
| ... | ... | 50+ 工具 |
这意味着什么? 当 AI 编程助手在生成代码前,会先读取这些规则文件,从而避免生成已知的反模式。这是从"事后诊断"到"事前预防"的范式转变。
五、死代码检测:找出项目中那些"僵尸代码"
除了 Lint 规则,React Doctor 还内置了强大的死代码检测能力。
5.1 检测范围
Dead Code Detection:
├── 未使用的导出(export but never imported)
├── 重复的类型定义(same interface in multiple files)
├── 冗余文件(files not referenced by any import chain)
├── 未使用的 CSS 类(class names not in JSX)
├── 无引用的常量(const declared but never used)
└── 废弃的 API 调用(deprecated methods still in codebase)
5.2 死代码如何影响评分
死代码在评分中属于 info 级别,每个扣 1 分。但大量死代码会严重影响评分——一个有 30 个未使用导出的项目,仅死代码就扣 30 分。
5.3 实战:检测大型项目的死代码
# 只检测死代码
npx -y react-doctor@latest . --no-lint
# 详细输出每个死代码项
npx -y react-doctor@latest . --no-lint --verbose
# 输出 JSON 格式,方便脚本处理
npx -y react-doctor@latest . --no-lint --json
JSON 输出示例:
{
"ok": true,
"score": { "score": 72, "label": "Needs Work" },
"diagnostics": [
{
"rule": "dead-code/unused-export",
"severity": "info",
"file": "src/utils/format.ts",
"line": 15,
"message": "'formatCurrency' is exported but never imported",
"suggestion": "Remove the export or add an import"
},
{
"rule": "dead-code/duplicate-type",
"severity": "info",
"file": "src/types/user.ts",
"line": 3,
"message": "'UserProps' is defined identically in src/components/UserCard.tsx:5",
"suggestion": "Import from a shared location"
}
]
}
六、CI/CD 集成:让代码质量成为团队门槛
6.1 GitHub Actions 集成
React Doctor 提供了官方的 Composite Action,一行配置即可集成到 CI/CD:
name: React Doctor
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
pull-requests: write # 在 PR 上发表评论
jobs:
react-doctor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # diff 检测需要完整历史
- uses: millionco/react-doctor@main
with:
diff: main
github-token: ${{ secrets.GITHUB_TOKEN }}
6.2 PR 评论效果
当 PR 提交时,React Doctor 会在 PR 上自动发表评论:
🏥 React Doctor Report
Score: 82/100 (Great)
Issues found: 5 errors, 3 warnings, 8 info
🔴 Errors:
- src/App.tsx:42 - no-cascading-set-state
→ Multiple setState calls in useEffect. Use single update.
- src/components/List.tsx:15 - no-array-index-as-key
→ Using array index as key. Use unique identifier.
🟡 Warnings:
- src/utils/api.ts:8 - no-inline-function-as-prop
→ Inline function passed as prop causes re-renders.
📊 Score breakdown:
State & Effects: -12 (2 errors, 2 warnings)
Performance: -6 (1 error, 1 warning)
Dead Code: -0 (0 items)
6.3 质量门槛配置
# 只要有 error 级别的问题就阻止合并
- uses: millionco/react-doctor@main
with:
fail-on: error
# warning 级别也阻止合并(严格模式)
- uses: millionco/react-doctor@main
with:
fail-on: warning
6.4 不使用 Marketplace Action 的替代方案
如果你的团队安全策略不允许第三方 Action,可以用 npx 形式:
- run: npx -y react-doctor@latest --fail-on warning
6.5 Pre-commit Hook
在 git commit 前自动检测:
# .husky/pre-commit
npx -y react-doctor@latest --staged --fail-on error
--staged 标志只检测暂存区的文件,速度极快。
七、oxlint + ESLint 双引擎:同一套规则,两种运行方式
React Doctor 的规则集同时以 oxlint 插件和 ESLint 插件的形式发布,你可以在现有 lint 基础设施中无缝集成。
7.1 oxlint 集成(推荐,50-100x 更快)
// .oxlintrc.json
{
"plugins": ["react-doctor"],
"rules": {
"react-doctor/no-derived-useState": "error",
"react-doctor/no-cascading-setState": "error",
"react-doctor/no-array-index-as-key": "error"
}
}
7.2 ESLint 集成(Flat Config)
// eslint.config.js
import reactDoctor from "react-doctor/eslint-plugin";
export default [
reactDoctor.configs.recommended, // 基础推荐
reactDoctor.configs.next, // Next.js 规则
reactDoctor.configs["react-native"], // React Native 规则
reactDoctor.configs["tanstack-start"], // TanStack Start 规则
reactDoctor.configs["tanstack-query"], // TanStack Query 规则
];
7.3 为什么需要双引擎?
| 维度 | oxlint | ESLint |
|---|---|---|
| 速度 | 50-100x 更快(Rust 实现) | 成熟但慢 |
| 生态 | 新,插件少 | 成熟,插件丰富 |
| CI | 推荐 | 也支持 |
| Pre-commit | 极快 | 可用 |
策略建议:本地开发用 oxlint(快速反馈),CI 中两者都跑(全面覆盖)。
八、程序化 API:将诊断嵌入你的工具链
React Doctor 提供了完整的 Node.js API,可以嵌入到自定义工具或脚本中:
8.1 基础用法
import { diagnose, toJsonReport, summarizeDiagnostics } from "react-doctor/api";
const result = await diagnose("./path/to/your/react-project");
console.log(result.score); // { score: 82, label: "Great" } 或 null
console.log(result.diagnostics); // Diagnostic[]
console.log(result.project); // 检测到的框架、React 版本等
8.2 生成结构化报告
const report = toJsonReport(result, { version: "1.0.0" });
const counts = summarizeDiagnostics(result.diagnostics);
console.log(counts);
// { errors: 5, warnings: 12, info: 23, total: 40 }
8.3 实战:自定义质量门禁
import { diagnose } from "react-doctor/api";
async function qualityGate(projectPath: string): Promise<boolean> {
const result = await diagnose(projectPath, {
lint: true,
deadCode: true,
});
if (!result.score || result.score.score < 75) {
console.error(`❌ Quality gate failed: score ${result.score?.score ?? 'N/A'}`);
return false;
}
const errorCount = result.diagnostics.filter(d => d.severity === 'error').length;
if (errorCount > 3) {
console.error(`❌ Too many errors: ${errorCount}`);
return false;
}
console.log(`✅ Quality gate passed: score ${result.score.score}`);
return true;
}
// 在 CI/CD 脚本中使用
const passed = await qualityGate('./my-project');
process.exit(passed ? 0 : 1);
九、配置详解:三层忽略粒度
React Doctor 的忽略配置是所有 Lint 工具中最精细的——三层嵌套,满足从"全局禁用"到"单文件单规则豁免"的所有需求。
9.1 配置文件
// react-doctor.config.json
{
"ignore": {
"rules": [
"react/no-danger",
"jsx-a11y/no-autofocus"
],
"files": [
"src/generated/**"
],
"overrides": [
{
"files": ["components/modules/diff/**"],
"rules": [
"react-doctor/no-array-index-as-key",
"react-doctor/no-render-in-render"
]
},
{
"files": ["components/search/HighlightedSnippet.tsx"],
"rules": ["react/no-danger"]
}
]
}
}
9.2 三层粒度对比
| 层级 | 配置项 | 效果 | 使用场景 |
|---|---|---|---|
| Level 1 | ignore.rules | 全局禁用某条规则 | 项目风格与规则冲突 |
| Level 2 | ignore.files | 禁用匹配文件的所有规则 | 自动生成的代码 |
| Level 3 | ignore.overrides | 仅对匹配文件禁用指定规则 | 单文件豁免,保留其他检测 |
Level 3 是最推荐的——它只豁免特定规则的特定文件,不影响其他规则的检测覆盖。
9.3 内联注释忽略
// 忽略下一行的特定规则
// react-doctor-disable-next-line react-doctor/no-cascading-set-state
useEffect(() => {
setA(value);
setB(value);
}, [value]);
// 忽略下一行的多个规则(逗号分隔)
// react-doctor-disable-next-line react-doctor/rerender-state-only-in-handlers, react-doctor/no-derived-useState
const [localSearch, setLocalSearch] = useState(searchQuery);
// JSX 中的块注释
{/* react-doctor-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html }} />
9.4 --explain:诊断忽略为何不生效
这是一个极具开发者体验的设计——当你加了忽略注释但规则仍然触发时:
npx -y react-doctor@latest --explain src/App.tsx:42
输出:
Diagnosis for src/App.tsx:42:
Rule: react-doctor/no-cascading-set-state
Severity: error
Suppression check:
Found nearby comment: react-doctor-disable-next-line react/no-danger
→ Comment targets a DIFFERENT rule (react/no-danger), not react-doctor/no-cascading-set-state
→ Fix: Use comma-separated form to cover both rules, or add a separate comment
No other suppressions found within 2 lines.
这比 ESLint 的"静默忽略"体验好太多了——它明确告诉你为什么忽略不生效,以及如何修复。
十、顶级开源项目评分榜:你的项目在哪个段位?
React Doctor 维护了一个公开的项目评分榜(基于 react-doctor-benchmarks 仓库),以下是知名 React 项目的评分:
| 排名 | 项目 | 评分 | 评价 |
|---|---|---|---|
| 1 | executor | 94 | Great |
| 2 | nodejs.org | 86 | Great |
| 3 | tldraw | 70 | Needs Work |
| 4 | t3code | 68 | Needs Work |
| 5 | better-auth | 64 | Needs Work |
| 6 | excalidraw | 63 | Needs Work |
| 7 | mastra | 63 | Needs Work |
| 8 | payload | 60 | Needs Work |
| 9 | typebot | 58 | Needs Work |
关键发现:
- 即使是顶级开源项目,多数也只拿到 60-70 分,说明 React 代码质量问题是普遍存在的
- nodejs.org 以 86 分领先,可能因为它是相对简单的 Next.js 站点
- tldraw、excalidraw 这种复杂交互项目分数偏低,复杂的 Canvas/Fiber 架构容易触发反模式
- AI Agent 生成的代码项目,通常在 40-55 分之间(Critical 级别)
十一、实战:从零诊断一个 AI 生成的 React 项目
11.1 创建测试项目
假设我们有一个 AI 编程助手生成的 React 项目:
// App.tsx - AI 生成的"典型"代码
import { useState, useEffect } from 'react';
function App() {
const [users, setUsers] = useState([]);
const [filteredUsers, setFilteredUsers] = useState([]);
const [searchQuery, setSearchQuery] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
// 反模式 #1: 获取数据后手动同步
useEffect(() => {
setIsLoading(true);
fetch('/api/users')
.then(res => res.json())
.then(data => {
setUsers(data);
setIsLoading(false);
})
.catch(err => {
setError(err);
setIsLoading(false);
});
}, []);
// 反模式 #2: 用 Effect 同步派生状态
useEffect(() => {
const filtered = users.filter(u =>
u.name.toLowerCase().includes(searchQuery.toLowerCase())
);
setFilteredUsers(filtered);
}, [users, searchQuery]);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<input
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
/>
{filteredUsers.map((user, index) => (
// 反模式 #3: 数组索引作为 key
<div key={index}>
<span>{user.name}</span>
</div>
))}
</div>
);
}
11.2 运行 React Doctor
npx -y react-doctor@latest .
输出:
🏥 React Doctor
Score: 38/100 (Critical)
Errors (4):
🔴 no-derived-useState
src/App.tsx:9 — 'filteredUsers' is derived from 'users' and 'searchQuery'
→ Compute directly: const filtered = users.filter(...)
→ This eliminates the Effect and extra renders
🔴 no-cascading-setState
src/App.tsx:13-18 — Multiple setState calls in single Effect
→ Batch updates or use a single state object
🔴 no-array-index-as-key
src/App.tsx:39 — Using array index as key in map()
→ Use user.id or other stable unique identifier
🔴 no-unnecessary-effect
src/App.tsx:25 — Effect only computes derived value
→ Replace with direct computation outside Effect
Warnings (2):
🟡 no-inline-function-as-prop
src/App.tsx:37 — Inline onChange handler creates new reference each render
→ Extract to useCallback or separate function
🟡 no-object-as-prop
(none in this example)
Info (3):
ℹ️ dead-code/unused-import
src/App.tsx:1 — 'useEffect' import could be removed after fixing above issues
ℹ️ dead-code/unused-variable
(2 other info items)
Suggested fixes:
1. Remove filteredUsers state and Effect, compute directly
2. Use user.id as key instead of index
3. Extract onChange handler
4. Use async/await with error boundary instead of .then chains
十二、在团队中推行 React Doctor
12.1 分阶段推行策略
Phase 1: 发现(1 周)
├── 全团队运行 npx react-doctor@latest . --score
├── 收集各项目的基线评分
└── 识别 Top 10 最严重问题
Phase 2: AI Agent 集成(1 周)
├── 运行 npx react-doctor@latest install
├── 所有开发者的 AI 编程工具自动获得规则
└── 新代码的质量立即提升
Phase 3: CI/CD 集成(2 周)
├── 添加 GitHub Action
├── 设置 fail-on: error
└── PR 自动评论诊断结果
Phase 4: 持续优化
├── 定期审查新问题,调整忽略规则
└── 目标:项目评分 > 80
十三、总结:React Doctor 是 AI 编程时代的"必装机"
React Doctor 解决了一个 2026 年最紧迫的问题:AI 编程助手在提升开发速度的同时,也在加速技术债的积累。
传统的 Lint 工具(ESLint、oxlint)是在"人类手写代码"的时代设计的,它们的规则集覆盖的是人类常见的错误模式。但 AI 生成的代码有自己独特的反模式——过度使用 Effect、不必要的 useState、级联状态更新、数组索引 key——这些是传统 Lint 工具没有专门针对的。
React Doctor 的三个核心创新:
- AI Agent 集成:从"事后诊断"到"事前预防",直接把最佳实践注入 AI 编程助手的知识库
- 健康评分:让代码质量可视化、可量化、可追踪——你无法管理你不能度量的东西
- 框架感知:Next.js / Vite / React Native 的规则自动切换,零配置开箱即用
对于一个使用 AI 编程助手的团队,React Doctor 不是"锦上添花",而是"必修课"。因为 AI 写代码很快,但修 AI 写的烂代码很慢——React Doctor 让你从一开始就写对。
开源地址:https://github.com/millionco/react-doctor
在线诊断:https://react.doctor
npm:npm install -g react-doctor
本文基于 React Doctor v1.x 版本分析,项目仍在快速迭代中。60+ 规则和评分算法可能随版本更新而调整。