没计划地重构 React 组件,结局通常是一个 400 行的重写,外加两个没人看得懂的测试挂掉。下面这些 Prompt 强制模型先点名具体异味(prop drilling、超长组件、误用 memo、server / client 混淆、effect 滥用),再给出”最小可行改动”和取舍——动手之前先讲清楚。要更通用的重构套路看 重构 Prompt。
这套 Prompt 适合用在哪
- 生产 React 代码
- Next.js / Astro 混合
- 上线前性能修复
- 加测试前准备
- 抽组件库
1. 异味识别
下面是 React 组件。请按优先级列 top 5 异味:每条说明问题、为什么生产环境会出问题、最小修复。先别重写。
{粘贴}
2. 抽自定义 hook
下面组件 UI 与逻辑混在一起。请把逻辑抽成自定义 hook。输出:(a) hook + 它的 API;(b) 简化后的组件;(c) hook 明确不负责什么;(d) hook 文件放哪里。
{粘贴}
3. 状态提升 / 下钻 重构
下面两个兄弟组件通过 3 层 prop drilling 共享状态。请提议正确的状态放置点:local / lifted / context / 外部 store。从 re-render 成本与归属清晰度论证。
{粘贴}
4. Server vs Client 拆分(Next.js App Router)
下面是混了 server 取数与 client 交互的 App Router 组件。请拆成 server 边界 + client 边界。输出:(a) 哪个文件加 "use client";(b) 数据如何跨界传递;(c) 什么不能跨边界。
{粘贴}
5. useMemo / useCallback 正确性审计
下面组件用了 useMemo / useCallback。逐处审计:(a) 真的需要 memo 吗;(b) 依赖数组对吗;(c) 是否因引用导致 re-render。标出可删除的、漏掉的。
{粘贴}
6. React.memo 审计
下面:父 + 3 子,子用了 React.memo。逐子检查:(a) memo 是否真省了渲染;(b) props 是否稳定;(c) 函数 / 对象 prop 是否打破 memo。删除无效 memo,给真正有用的加 equality fn。
{粘贴}
7. useEffect 简化
下面组件有 {N} 个 useEffect。每个判定:(a) 必要 vs 应改成派生状态 / 事件处理 / 外部 store;(b) 有没有竞态;(c) 替代方案。目标:至少减半。
{粘贴}
8. 表单控件重构
下面表单有 {N} 个受控输入。请重构:(a) 一致的 change handler 模式;(b) 校验位置(按字段 vs schema);(c) 异步提交生命周期;(d) 可访问性。给前后对比。
{粘贴}
9. Render-prop / HOC → hook 迁移
下面组件使用 render-props 或 HOC。请迁移到自定义 hook。输出:(a) hook;(b) 新组件;(c) 使用方需变更的位置。
{粘贴}
10. 长组件拆分
下面是一个 {N} 行组件。请提议合理拆分。每个拆分给:名字、它拥有的 props、内部保留什么。避免过度抽象——每个拆分都要给真实理由。
{粘贴}
11. Context vs Store 决策
下面组件用 React Context 共享 {state}。请评估:(a) Context 合适,还是 Zustand / Jotai / Redux;(b) re-render 成本;(c) 哪些会迁移、哪些保留。给结论 + 迁移草图。
{粘贴}
12. 可测试性重构
下面组件难以测试。请重构提升可测试性:(a) 抽纯函数;(b) 隔离副作用;(c) 替换不可 mock 的部分。输出重构后组件 + 3 个测试骨架。
{粘贴}
13. Suspense / Error Boundary 放置
下面是含异步数据的组件树。请提议 Suspense 与 Error Boundary 的放置位置。输出:带边界标注的树状图 + 每处的理由。
{粘贴}
容易踩的坑
- 直接重写而不是重构——会丢掉那些没人写注释的修复
- 没度量就到处加 React.memo / useMemo / useCallback——大多没用甚至更慢
- 过度拆成 6 个小组件,其实 2 个就够——过早抽象比保留异味更糟
- 两个兄弟一旦要共享状态就立刻丢全局 store
- App Router 里不讨论 server / client 边界,然后被 “use client” 级联连锁坑掉一天
- 用另一个 useEffect 替换 useEffect——其实应该改成派生状态或事件处理