它说的就是在骂我
做情绪 Dashboard 的前端用 Next.js + React,Claude Code 帮我写了大半年。
上周发现页面滚动开始有点卡,股票列表组件一动就全量重渲染,情绪折线图每次切换标的要等将近一秒。我当时的判断是:数据量变大了,正常现象。
然后刷 GitHub Trending,react-doctor 跳出来了。790k 下载量,millionco 出品。点进去,第一句话:
"你的代理编写了错误的 React 代码,这个功能可以捕获到它。"
我看了三秒。
翻译成人话就是:react-doctor 专门设计来抓 AI 编程助手(Cursor、Claude Code、GitHub Copilot 这些)写出来的 React 反模式。不是说 AI 不行——是说 AI 生成的 React 代码有一套特定的、高频出现的错误模式,react-doctor 针对这些模式做了专项检测。
一条命令扫下去,输出 0 到 100 的健康评分 + 可操作的诊断报告。
我的情绪 Dashboard 跑出来:63 分。
(我沉默了大概四秒。)
17 个问题。Claude Code 帮我写的前端,被 react-doctor 找出来 17 个坑。然后我又让 Claude Code 把坑填了——这个闭环有点离谱,但确实好用。
国内订阅claude code的确实有点困难,建议大家找一个有售后的平台:claudemax.shop
结论先行
情绪 Dashboard(Next.js 14 + React 18,约 8000 行组件代码)跑 react-doctor:
- 初次扫描:63 / 100,17 个问题
- Claude Code 修复一个下午后:89 / 100,剩 4 个可接受的低优先级警告
- 页面首屏加载:4.1s → 2.3s
- 股票列表滚动帧率:43fps → 58fps
评分:9 / 10。强烈推荐所有重度使用 AI 编程的 React 项目装上跑一遍。
唯一的但是:v0.1.6,还很早期,部分规则有误报,不要照单全收。
一条命令,先跑起来
不需要安装,直接在项目根目录跑:
npx -y react-doctor@latest .
Next.js 项目会自动识别。如果是 Vite 或者 React Native,加参数:
npx -y react-doctor@latest . --framework vite
npx -y react-doctor@latest . --framework react-native
扫描大概 20-30 秒,输出一份健康报告。报告里有总评分、按优先级排列的问题列表、每个问题的文件位置和修复建议。
然后把那份报告贴进 Claude Code,说"帮我修这些问题",就进入真正有意思的部分了。
Claude Code 写的 React,被 react-doctor 扫出了什么
第一份诊断报告:17 个坑,Claude Code 是主要供应商
63 分的报告出来,我做的第一件事是统计:这 17 个问题里有多少是我手写的,有多少是 Claude Code 写的。
翻了一下 git log,结论很清楚:14 个是 Claude Code 写的组件里出的,3 个是我自己手写的。
没有批评 Claude Code 的意思。AI 编程助手写 React 有几个高频反模式,react-doctor 的规则集里针对的就是这些:
第一类,useEffect 依赖数组漏掉了该写的依赖。Claude Code 生成 useEffect 的时候,经常把依赖数组写得比实际需要的少,结果是 effect 不该跑的时候跑了,或者该更新的时候没更新。这种 bug 很隐蔽,功能看起来 OK,但行为不稳定。我的 Dashboard 里有 6 个这样的 useEffect。
第二类,在 JSX 里直接创建对象和函数。比如:
// Claude Code 经常这么写
<StockChart
config={{ type: 'line', color: '#2563eb' }} // 每次渲染新对象
onHover={() => setHovered(true)} // 每次渲染新函数
/>
这两行看起来没问题,但每次父组件渲染,config 和 onHover 都是全新的引用,子组件的 memo 完全失效,必然触发重渲染。我的 Dashboard 里有 5 个这样的组件,情绪折线图那个卡顿的根本原因就在这里。
第三类,列表渲染里用了 index 当 key。这个大家都知道不该这么做,但 Claude Code 在不确定数据结构的时候,经常默认用 key={index} 打发了事。
react-doctor 把这 17 个问题按优先级分了三档,最高优先级的 8 个直接影响性能,Claude Code 扫出来的诊断报告写得很清楚,哪个文件哪一行,问题是什么,怎么修。
useEffect 依赖数组:AI 最爱挖的坑,也最容易批量修
把 react-doctor 的诊断报告复制,贴进 Claude Code 的对话框,说一句话:"帮我修这 8 个高优先级问题,每修完一个给我看修改内容"。
Claude Code 处理 useEffect 依赖的方式很稳。以情绪数据加载那个组件为例:
// 修前(react-doctor 标记为高优先级)
useEffect(() => {
fetchSentiment(symbol, dateRange);
setLoading(true);
}, []); // 依赖数组空的,symbol 和 dateRange 变了也不会重新 fetch
// 修后
useEffect(() => {
fetchSentiment(symbol, dateRange);
setLoading(true);
}, [symbol, dateRange, fetchSentiment]); // 完整依赖
但 Claude Code 修的时候会遇到一个常见问题:fetchSentiment 如果是在组件里定义的函数,每次渲染都是新引用,加进依赖数组会导致死循环。
它处理这种情况的方式是自动把 fetchSentiment 包进 useCallback:
const fetchSentiment = useCallback(
async (symbol: string, dateRange: DateRange) => {
// 原来的函数体
},
[baseUrl] // fetchSentiment 真正依赖的东西
);
这一步如果我自己修,很容易漏掉,或者 useCallback 的依赖数组又写错了。Claude Code 一次处理完,然后让我 review,基本没有问题。
6 个 useEffect 问题,大概花了 40 分钟,全部修完,行为跟之前一致,但现在 symbol 切换会正确触发数据重新加载了——这个 bug 我之前没注意到,react-doctor 顺手给我找出来了。
JSX 内联对象和函数:memo 失效的根本原因
这一块才是性能问题的主因。
情绪折线图组件用了 React.memo,但每次父组件重渲染它还是会跟着渲,原因就是父组件里有这样的代码:
// 问题代码:每次渲染,chartOptions 是新对象
<SentimentChart
data={sentimentData}
options={{ smoothing: true, showGrid: false, color: theme.primary }}
onPointClick={(point) => handlePointClick(point, symbol)}
/>
Claude Code 修复的方案是把这两个移到 useMemo 和 useCallback 里:
const chartOptions = useMemo(
() => ({ smoothing: true, showGrid: false, color: theme.primary }),
[theme.primary]
);
const handleChartPointClick = useCallback(
(point: DataPoint) => handlePointClick(point, symbol),
[handlePointClick, symbol]
);
<SentimentChart
data={sentimentData}
options={chartOptions}
onPointClick={handleChartPointClick}
/>
改完之后,SentimentChart 的 memo 终于生效了。切换标的的时候,只有 data 变了才重渲染,options 没变就跳过。
情绪折线图的那个 1 秒卡顿消失了。帧率从 43fps 到 58fps,这一个修改贡献了大概一半的性能提升。
修完 8 个高优先级问题,重新跑 react-doctor:82 分。继续处理中优先级的 6 个,最终跑到 89 分。
修完之后,再把 react-doctor 接进开发流程
跑了一遍修完,这东西最大的价值不是事后修,而是接进日常流程防止 AI 继续挖坑。
我现在的做法:每次 Claude Code 生成一批 React 组件之后,跑一次 react-doctor,看看分数有没有掉。分数掉了就立刻让 Claude Code 解释并修复,不让问题积累。
也可以接进 pre-commit hook,但我嫌每次 commit 都扫一遍太慢。现在的节奏是:每次 AI 写完一个功能模块跑一次,大概两天一次,够用了。
还有一个额外收获:react-doctor 的诊断报告可以作为 Claude Code 的系统提示的一部分。我现在跑完扫描,把"常见问题类型"那一节贴进 CLAUDE.md 的写作规范——不,是贴进项目的 CLAUDE.md,告诉 Claude Code:"以下是这个项目的 React 反模式清单,写新组件的时候主动避免"。效果比事后修要好得多。
说实话,它现在还不完美
误报是真实存在的。 我 89 分里剩下的 4 个问题,review 之后发现有 2 个是误报——react-doctor 把一个刻意使用 index 作为 key 的场景(静态列表,不会重排序)标记为高优先级问题。v0.1.6 的规则还比较粗,上下文感知能力有限,遇到这种情况要自己判断。
只做静态分析,运行时问题看不到。 react-doctor 扫的是代码层面的反模式,但有些性能问题是运行时才暴露的——比如数据量大了之后的渲染压力、真实网络延迟下的 loading 状态处理。这类问题还是得靠 React DevTools Profiler 或者 Lighthouse。
没有 CI 集成。 现在只能手动跑,没有 GitHub Actions 的官方 action,想接进自动化流程要自己写脚本。应该快了,但现在还没有。
重度使用 AI 编程的 React 项目,这件事值得认真对待
react-doctor 被设计出来,背后有一个值得认真看的现象:AI 编程助手生成的代码有系统性的盲区。
不是 Claude Code 或者 Copilot 不够聪明。是 AI 在生成代码的时候,无法感知代码运行之后的性能影响,也无法在跨多个文件的上下文里追踪引用变化。所以它会合理地写出一段"在当前视角下正确"的代码,但这段代码放到整个应用的渲染树里会引发连锁的性能问题。
对量化 / 金融 AI 项目来说,这个问题更值得重视。情绪 Dashboard 这类应用有几个特点:数据更新频率高(几秒一次),组件树深(数据 → 图表 → 指标 → 信号),用户对延迟敏感(盘中看数据,卡顿直接影响决策)。在这种场景下,React 渲染效率的下降不只是体验问题,是功能问题。
react-doctor 出现得很及时。它把"AI 代码质量审计"这件事变成了一条命令,把一个需要经验丰富的 React 工程师花几小时做的 code review,压缩成了一份可以直接喂给 Claude Code 去修的诊断报告。
这种"AI 生成 → 工具审计 → AI 修复"的闭环,会成为 AI 编程时代的标配工作流,不只是 React。
你是哪种情况
在用 Claude Code / Cursor / Copilot 写 React 的:现在就去跑一遍 npx -y react-doctor@latest .。不管分数多少,先知道自己的代码库是什么状态。很可能你会有跟我一样的"沉默四秒"的体验。
React 项目超过 3000 行组件代码的:性能反模式的积累是指数级的,早发现早修比后面大规模重构省力得多。react-doctor 的报告可以直接作为 Claude Code 的修复任务列表,一个下午能清掉大部分高优先级问题。
刚开始用 AI 写前端、还没写多少代码的:先把 react-doctor 的常见问题清单读一遍(GitHub 上有详细的规则说明),然后把这些反模式写进你的 CLAUDE.md 或者 Cursor 的 Rules,从源头防止 AI 引入这些问题,比事后扫修要轻松。
最后
AI 写代码,人来审计,AI 再修——这个流程不是妥协,是合理的分工。
react-doctor 做的事情是把"React 代码质量审计"这件以前需要资深工程师的事情,变成了一条命令。结合 Claude Code 的修复能力,情绪 Dashboard 从 63 分到 89 分用了一个下午。
如果你也在用 AI 写 React,或者在做量化 / 金融 AI 的前端工具,评论区聊。react-doctor 接进 CLAUDE.md 的那套方法我也可以整理一下分享出来。