react-audit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Audit
React 审计
Purpose
目的
Deep review of React code across three tracks: architectural analysis inline, mechanical convention
checks in a subagent, and — when the binary is reachable — react-doctor. Finds and reports; it never
edits. Applying what it finds is 's job, or the caller's.
review:code-cleanupLinter-aware. Biome and ESLint already own hook rules, dependency arrays, self-closing elements,
fragments, type imports, and unused variables. This skill skips all of it.
从三个维度深度审查React代码:内联架构分析、子代理执行的机械规范检查,以及(当可获取二进制文件时)react-doctor工具检测。仅发现问题并生成报告,绝不修改代码。后续问题修复由技能或调用者完成。
review:code-cleanup兼容代码检查工具。Biome和ESLint已覆盖hook规则、依赖数组、自闭合元素、片段、类型导入和未使用变量等场景,本技能会跳过所有这些检查。
When to Use
使用场景
- After building or reworking a React feature, before it is committed
- Reviewing a change that touches components, hooks, or state
- A component works but has become hard to reason about — unexplained re-renders, an effect chain nobody wants to touch, a file that keeps growing
- Invoked as a stack lens by when the diff contains React files
review:changes-review
Trigger phrases: "review react", "audit react", "check components", "react patterns", "effects
review", "why does this re-render".
- 完成React功能开发或重构后,提交代码前
- 审查涉及组件、hook或state的变更
- 组件可正常运行但难以维护——存在无法解释的重渲染、没人敢修改的effect链、持续膨胀的文件
- 当差异包含React文件时,由作为堆栈透镜调用
review:changes-review
触发短语:"review react"、"audit react"、"check components"、"react patterns"、"effects review"、"why does this re-render"。
Commands
命令
| Command | Scope |
|---|---|
| Staged and unstaged changes |
| One file |
| A directory |
| 命令 | 作用范围 |
|---|---|
| 暂存和未暂存的变更 |
| 单个文件 |
| 目录 |
Phase 1: Load Context
阶段1:加载上下文
1.1 Confirm this is a React project
1.1 确认这是React项目
Check for a dependency. If there is none, stop and say so — do not audit a
non-React codebase against React rules.
package.jsonreact检查中是否存在依赖项。如果不存在,则停止操作并告知用户——不要针对非React代码库执行React规则审计。
package.jsonreact1.2 Detect the React version and the compiler
1.2 检测React版本和编译器
Both gate which findings are even valid, so resolve them before analysis, not during it.
bash
jq -r '.dependencies.react // .devDependencies.react // "none"' package.json
grep -rl "babel-plugin-react-compiler\|reactCompiler" --include="*.config.*" --include="package.json" . | head -3- React 19+ — ,
useActionStatefor pending state,useTransitionas a plain prop, ref callback cleanups, andrefare all available.use()is stable from 19.2.useEffectEvent - React 18 — none of the above. Do not recommend them.
- React Compiler enabled — skip every memoization finding. The compiler inserts memoization
itself, so /
useMemo/useCallbackadvice is noise there.memo
Carry all three answers into Phase 2; the reference files describe how each one gates their rules.
这两项决定了哪些检查结果有效,因此需在分析前完成解析,而非分析过程中。
bash
jq -r '.dependencies.react // .devDependencies.react // "none"' package.json
grep -rl "babel-plugin-react-compiler\|reactCompiler" --include="*.config.*" --include="package.json" . | head -3- React 19+ — 支持、用于待处理状态的
useActionState、作为普通属性的useTransition、ref回调清理函数以及ref。use()从19.2版本开始稳定。useEffectEvent - React 18 — 不支持上述所有特性,请勿推荐使用。
- 启用React Compiler — 跳过所有记忆化相关检查。编译器会自动插入记忆化逻辑,因此/
useMemo/useCallback相关建议属于无效信息。memo
将这三个结果带入阶段2;参考文件描述了每个结果如何约束规则。
1.3 Read project rules
1.3 读取项目规则
Read these if they exist, skip silently if not:
.cursor/rules/react.mdc
.cursor/rules/typescript.mdc
.cursor/rules/stores.mdc
.claude/rules/react.md
.claude/rules/typescript.mdWith no project rules, fall back to the defaults in .
references/如果存在以下文件则读取,不存在则静默跳过:
.cursor/rules/react.mdc
.cursor/rules/typescript.mdc
.cursor/rules/stores.mdc
.claude/rules/react.md
.claude/rules/typescript.md若无项目规则,则回退到目录中的默认规则。
references/1.4 Detect conventions
1.4 检测约定规范
bash
grep -rl "\.displayName\s*=" src/ --include="*.tsx" | head -3
grep -rl "data-component" src/ --include="*.tsx" | head -3- found in 2+ files → activate the
displayNameanddisplayNamechecksdata-component - Not found → skip both entirely, so projects without the convention get no false positives
- ,
props-naming,variable-order, andcomponent-props-refare always activedestructuring
bash
grep -rl "\.displayName\s*=" src/ --include="*.tsx" | head -3
grep -rl "data-component" src/ --include="*.tsx" | head -3- 在2个及以上文件中发现→ 启用
displayName和displayName检查data-component - 未发现 → 完全跳过这两项检查,避免对无此约定的项目产生误报
- 、
props-naming、variable-order和component-props-ref始终启用destructuring
1.5 Identify target files
1.5 确定目标文件
- given → that file or directory
$ARGUMENTS - Otherwise → plus
git diff --name-only HEADgit diff --name-only --cached - Filter to and
.tsxfiles that import React.ts - Read every target file before analyzing it
If the filter leaves nothing, report that there are no React files in scope and stop.
- 指定了→ 对应文件或目录
$ARGUMENTS - 未指定 → 加上
git diff --name-only HEAD的结果git diff --name-only --cached - 过滤出导入了React的和
.tsx文件.ts - 分析前读取所有目标文件
如果过滤后无结果,则报告范围内没有React文件并停止操作。
Phase 2: Dispatch Tracks
阶段2:分配检测任务
Start all applicable tracks at once so they run concurrently.
同时启动所有适用的检测维度,使其并行运行。
Track A: react-doctor (optional)
维度A:react-doctor(可选)
An external binary, so treat it as a bonus rather than a dependency. Create a summary file and a
diagnostics directory with , then run the bundled script with the scope that matches
Phase 1.5:
mktempbash
bash <skill-dir>/scripts/run-react-doctor.sh . "$OUT" "$DIAG" --scope files --include-untracked| Phase 1.5 resolved | Scope args |
|---|---|
| Working-tree changes | |
| A file or directory | none — react-doctor scans the project, so filter its findings to the target paths in Phase 3 |
| A base ref (lens mode) | |
The script needs nothing installed. It prefers a react-doctor already in the project or on ,
then falls back to , , or to fetch it for the run. is first on purpose:
it resolves from its own cache, where will populate the nearest when it finds a
above the working directory — a side effect an audit should not have. It writes nothing into the
project and opts out of telemetry, the score API, and crash reporting, so no source metadata leaves
the machine — drop from the script if you want the 0-100 health score back and the
network call that computes it is acceptable.
PATHbunxpnpm dlxnpxbunxnpxnode_modulespackage.json--no-scoreRead , not the terminal summary. It is an array of objects with
, , , , , , , , and —
everything Phase 3 needs to merge and dedupe, with no text to parse:
$DIAG/diagnostics.jsonfilePathlineendLineruleseveritycategorytitlemessagehelpbash
jq -r '.[] | "\(.filePath):\(.line) [\(.category)/\(.severity)] \(.rule) — \(.title)"' "$DIAG/diagnostics.json"The directory also holds one per triggered rule, each with the rule's fix guidance and a docs
URL. Read those only for rules you are about to report.
.txtExit code says whether the tool ran, never whether the code is clean. A warning-level finding
still exits 0. Always read .
diagnostics.json| Exit | Meaning | Do |
|---|---|---|
| 3 | No react-doctor binary and no bunx/pnpm/npx to fetch one | Skip Track A, continue |
| 4 | Present but would not start — offline, or resolution failed | Skip Track A, continue |
| 0 or 1 | Ran | Read |
A skipped Track A is normal, not an error. Never install anything to satisfy it, never retry, and
never block the other tracks on it. The report says the track was skipped and why; Tracks B and C
carry the audit on their own.
Run it in the background if the host supports that — the other tracks do not depend on it.
这是一个外部二进制工具,因此将其视为额外检测项而非依赖项。使用创建摘要文件和诊断目录,然后运行捆绑脚本,作用范围与阶段1.5一致:
mktempbash
bash <skill-dir>/scripts/run-react-doctor.sh . "$OUT" "$DIAG" --scope files --include-untracked| 阶段1.5解析结果 | 作用范围参数 |
|---|---|
| 工作树变更 | |
| 单个文件或目录 | 无 — react-doctor会扫描整个项目,因此在阶段3中过滤出目标路径的结果 |
| 基准引用(透镜模式) | |
该脚本无需安装任何依赖。优先使用项目中已存在或中的react-doctor,若不存在则依次使用、或临时获取。优先选择是因为它从自身缓存解析,而在找到工作目录上方的时会将依赖安装到最近的中——这是审计不应产生的副作用。脚本不会向项目写入任何内容,且禁用遥测、评分API和崩溃报告,因此不会有源代码元数据离开本地机器——如果您需要0-100的健康评分且接受计算该评分的网络请求,可以从脚本中移除参数。
PATHbunxpnpm dlxnpxbunxnpxpackage.jsonnode_modules--no-score读取,而非终端摘要。 该文件是包含、、、、、、、和的对象数组——包含阶段3合并和去重所需的所有信息,无需解析文本:
$DIAG/diagnostics.jsonfilePathlineendLineruleseveritycategorytitlemessagehelpbash
jq -r '.[] | "\(.filePath):\(.line) [\(.category)/\(.severity)] \(.rule) — \(.title)"' "$DIAG/diagnostics.json"该目录还包含每个触发规则对应的文件,其中包含规则的修复指南和文档URL。仅在准备报告对应规则时读取这些文件。
.txt退出代码仅表示工具是否运行,绝不代表代码是否无问题。 警告级别的结果仍会返回退出码0。务必读取文件。
diagnostics.json| 退出码 | 含义 | 处理方式 |
|---|---|---|
| 3 | 无react-doctor二进制文件,且无bunx/pnpm/npx可用于获取 | 跳过维度A,继续执行其他任务 |
| 4 | 工具存在但无法启动——离线或解析失败 | 跳过维度A,继续执行其他任务 |
| 0或1 | 工具已运行 | 读取 |
跳过维度A属于正常情况,并非错误。绝不安装任何依赖以满足该维度需求,绝不重试,且绝不因该维度而阻塞其他维度。报告中需说明该维度被跳过的原因;维度B和C会继续完成审计任务。
如果主机支持,可在后台运行该维度——其他维度无需依赖其结果。
Track B: Mechanical checks (subagent)
维度B:机械检查(子代理)
- Read for the prompt template
references/mechanical-checks-prompt.md - Read for the rules
references/rules-conventions.md - Replace with only the conventions Phase 1.4 activated, and
{{CONVENTIONS}}with the target paths{{FILE_LIST}} - Dispatch a subagent with that prompt to scan the target files against the active convention rules and return structured violations, each with a file, a line, and the rule it breaks
These are read-only pattern matches, so a cheap subagent is enough. If the host has no subagent
facility, run the same prompt inline.
- 读取获取提示模板
references/mechanical-checks-prompt.md - 读取获取规则
references/rules-conventions.md - 将替换为阶段1.4启用的约定规范,将
{{CONVENTIONS}}替换为目标路径{{FILE_LIST}} - 使用该提示分配子代理,扫描目标文件是否违反启用的约定规则,并返回结构化的违规信息,每条信息包含文件、行号和违反的规则
这些是只读模式匹配,因此使用轻量级子代理即可。如果主机无子代理功能,则直接运行该提示。
Track C: Deep analysis (inline)
维度C:深度分析(内联)
Load and , then analyze each target file:
references/rules-effects.mdreferences/rules-patterns.mdEffects — the 16 anti-patterns in . Flag each with its number and the fix.
Patterns 15 and 16 are React 19-only; #4 is void when the compiler is on.
rules-effects.mdPatterns — memoization strategy (skip entirely under the compiler), in dependency
arrays, ref callbacks and their cleanups, early returns versus conditional rendering, throttle and
debounce construction, context splitting, data fetching in effects over ~15 lines, components over
200 lines, and related calls that should be a .
ref.currentuseStateuseReducer加载和,然后分析每个目标文件:
references/rules-effects.mdreferences/rules-patterns.mdEffect检查 — 中的16种反模式。标记每种反模式的编号和修复方案。模式15和16仅适用于React 19;启用编译器时模式4无效。
rules-effects.md模式检查 — 记忆化策略(启用编译器时完全跳过)、依赖数组中的、ref回调及其清理函数、提前返回与条件渲染、节流和防抖构造、上下文拆分、effect中超过15行的数据获取逻辑、超过200行的组件,以及应改为的相关调用。
ref.currentuseReduceruseStatePhase 3: Collect and Merge
阶段3:收集与合并
- Read if Track A ran, whatever its exit code, and filter to the target paths. Treat each entry as a hypothesis, not a verdict: open the file at
$DIAG/diagnostics.jsonand confirm it before reporting, the same standard Track C is held toline - Collect the Track B violations
- Combine with Track C
Deduplicate. Same file, same line range, same category from more than one track: keep the most
detailed version and record every track that found it. react-doctor and Track C overlap most — a
diagnostic and Effects #13 are usually one finding, and react-doctor's
text plus the rule's file often sharpen the fix Track C would have written alone.
no-fetch-in-effecthelp.txtDrop what is out of scope. Anything Biome or ESLint already reports, and anything outside the
target paths.
- 如果维度A已运行,无论退出码如何,读取并过滤出目标路径的结果。将每条结果视为假设而非结论:打开文件定位到对应行号并确认后再报告,遵循与维度C相同的标准
$DIAG/diagnostics.json - 收集维度B的违规信息
- 与维度C的结果合并
去重。同一文件、同一行范围、同一分类的多个维度结果:保留最详细的版本,并记录所有发现该问题的维度。react-doctor和维度C的重叠最多——诊断和Effect #13通常是同一问题,react-doctor的文本加上规则的文件通常会优化维度C原本的修复建议。
no-fetch-in-effecthelp.txt移除超出范围的内容。Biome或ESLint已报告的内容,以及目标路径之外的内容。
Phase 4: Output
阶段4:输出
Buckets
分类桶
| Bucket | Holds | Ordering |
|---|---|---|
| Critical | Causes a bug or wrong behavior — races, stale closures, effects that fire wrong | First |
| Improvements | Architecture and pattern changes that are judgment calls | Second |
| Conventions | Project convention violations from Track B | Last, always |
Conventions rank below everything else and never gate anything. They are cleanup-shaped, not
correctness-shaped: report them so the picture is complete, then hand them to ,
which is the skill that actually applies changes.
review:code-cleanup| 分类桶 | 包含内容 | 排序 |
|---|---|---|
| 严重问题 | 导致bug或错误行为的问题——竞态条件、过时闭包、错误触发的effect | 首位 |
| 优化建议 | 架构和模式变更的判断性建议 | 第二位 |
| 规范问题 | 维度B发现的项目约定违规 | 最后,始终 |
规范问题优先级低于所有其他内容,且绝不阻塞任何操作。 这些属于清理类问题,而非正确性问题:报告这些问题以确保信息完整,然后交由技能处理,该技能负责实际修改代码。
review:code-cleanupFinding format
问题格式
markdown
undefinedmarkdown
undefinedpath/to/Component.tsx
path/to/Component.tsx
Critical
严重问题
1. Race condition in fetch effect () [Effects #13]
Current: Raw fetch in useEffect without cleanup — a stale response can overwrite a fresh one
Fix: Add an ignore flag in the cleanup, or move to the project's query library
Found by: Deep analysis, react-doctor
Component.tsx:45-581. fetch effect中的竞态条件 () [Effects #13]
当前情况: useEffect中直接使用fetch且无清理逻辑——过时响应可能覆盖最新响应
修复方案: 在清理函数中添加忽略标记,或迁移到项目的查询库
发现来源: 深度分析、react-doctor
Component.tsx:45-58Improvements
优化建议
2. Extract data fetching to a custom hook () [Patterns]
Current: 40 lines of fetch logic in the component body
Fix: , following the project's existing pattern
Found by: Deep analysis
Component.tsx:30-72useItemDatause*Data2. 将数据提取逻辑抽离为自定义hook () [Patterns]
当前情况: 组件体中包含40行fetch逻辑
修复方案: 创建,遵循项目已有的模式
发现来源: 深度分析
Component.tsx:30-72useItemDatause*DataConventions
规范问题
3. Missing displayName () [displayName]
Fix:
Found by: Mechanical check
Component.tsxComponent.displayName = COMPONENT_NAME;undefined3. 缺少displayName () [displayName]
修复方案:
发现来源: 机械检查
Component.tsxComponent.displayName = COMPONENT_NAME;undefinedSummary table
摘要表格
After the file sections:
markdown
undefined文件部分之后:
markdown
undefinedSummary
摘要
Tracks: deep analysis, mechanical checks. react-doctor skipped (exit 3 — no runner available).
React 19.1, compiler off.
| # | Finding | Bucket | Location | Found by |
|---|---|---|---|---|
| 1 | Race condition in fetch effect | Critical | | Deep, RD |
| 2 | Extract data fetching to a hook | Improvement | | Deep |
| 3 | Missing displayName | Convention | | Mech |
**Always open with the track line.** Which tracks ran, which were skipped and why, the React
version, and whether the compiler is on. A reader cannot judge coverage without it.
The setup recommendation, when it applies, goes after this table — see the next section. Nothing
else follows the findings.检测维度:深度分析、机械检查。react-doctor已跳过(退出码3 — 无可用运行器)。
React版本19.1,未启用编译器。
| 序号 | 问题描述 | 分类桶 | 位置 | 发现来源 |
|---|---|---|---|---|
| 1 | fetch effect中的竞态条件 | 严重问题 | | 深度分析、RD |
| 2 | 将数据提取逻辑抽离为hook | 优化建议 | | 深度分析 |
| 3 | 缺少displayName | 规范问题 | | 机械检查 |
**始终以维度信息开头。** 哪些维度已运行、哪些被跳过及原因、React版本、是否启用编译器。读者无法在不了解这些信息的情况下判断覆盖范围。
适用的永久设置建议放在该表格之后——见下一节。结果之后无其他内容。No findings
无问题场景
markdown
undefinedmarkdown
undefinedReact audit: clean
React审计:无问题
Tracks: deep analysis, mechanical checks, react-doctor. React 19.1, compiler off.
4 files in scope, no findings.
---检测维度:深度分析、机械检查、react-doctor。React版本19.1,未启用编译器。
范围内共4个文件,未发现问题。
---Recommending a Permanent Setup
推荐永久设置
The audit itself never installs anything. Track A always uses the ephemeral runner — fetched for
the run, cached outside the project, gone afterwards. That holds even when you are about to
recommend a permanent setup, and it holds if the user says yes: they run the install, not you.
A permanent setup is worth recommending anyway, because the ephemeral run is a snapshot. Installed,
react-doctor runs from a script, scans each PR in CI, and is available to the agent between
audits.
doctorRecommend it when all of these hold:
- The repo is large enough to keep paying off. 20+ React files, or an established component tree. A handful of components does not need a CI gate
- Nothing already sets it up. No , no
doctor.config.{ts,mts,cts,js,mjs,cjs,json,jsonc}key inreactDoctor, no react-doctor dependency, no react-doctor CI workflowpackage.json - The scan actually found something. Recommend on any -severity entry in
error, or on a real volume ofdiagnostics.json-severity ones. A clean scan is an argument against the recommendation, not for itwarning
bash
jq -r 'group_by(.severity)[] | "\(.[0].severity): \(length)"' "$DIAG/diagnostics.json"Put it at the very end — the last lines of the output, after the summary table and after every
finding. It is a suggestion about tooling, and it must never sit between the reader and the findings
they came for:
react-doctor found N issues here (E errors, W warnings) and is not set up in this repo.adds it as a dev dependency, abunx react-doctor@latest installpackage script, a skill for your agents, and a CI workflow that scans each pull request.doctor
Recommend it, never run it — including with . Observed behavior of in
0.9.12: it adds a script and a devDependency to , writes a
lockfile, populates , adds , and drops a skill
directory into the config directory of every agent it detects. printed a "would install"
list and the same writes still landed, so treat it as an install, not a preview. This skill does not
make repo-wide changes.
--dry-runinstalldoctorreact-doctorpackage.jsonnode_modules.github/workflows/react-doctor.yml--dry-runSay it once, and drop it if the user has declined before.
审计本身绝不安装任何内容。 维度A始终使用临时运行器——运行时获取,缓存到项目外,运行后销毁。即使您即将推荐永久设置,即使用户同意,也需由用户执行安装操作,而非本技能。
仍值得推荐永久设置,因为临时运行只是快照。安装后,react-doctor可通过脚本运行,在CI中扫描每个PR,且在审计间隙可供代理使用。
doctor当所有以下条件满足时推荐:
- 仓库规模足够大,能持续获益。 20个及以上React文件,或成熟的组件树。少量组件无需CI检查
- 尚未设置该工具。 无文件、
doctor.config.{ts,mts,cts,js,mjs,cjs,json,jsonc}中无package.json键、无react-doctor依赖、无react-doctor CI工作流reactDoctor - 扫描确实发现了问题。 当中存在任何
diagnostics.json级别的条目,或大量error级别的条目时推荐。无问题扫描结果是反对推荐的理由,而非支持理由warning
bash
jq -r 'group_by(.severity)[] | "\(.[0].severity): \(length)"' "$DIAG/diagnostics.json"放在最后 — 输出的最后几行,在摘要表格和所有问题之后。这是关于工具的建议,绝不能放在读者关注的问题之前:
react-doctor在此处发现了N个问题(E个错误,W个警告),且本仓库尚未设置该工具。会将其添加为开发依赖、添加bunx react-doctor@latest install包脚本、为代理添加技能,以及添加扫描每个拉取请求的CI工作流。doctor
仅推荐,绝不执行——包括。 0.9.12版本中的实际行为:向添加脚本和开发依赖、写入锁文件、填充、添加,并向检测到的每个代理的配置目录中添加技能目录。会打印“将要安装”的列表,但仍会执行上述写入操作,因此将其视为安装操作,而非预览。本技能不会对仓库进行全局修改。
--dry-runinstallpackage.jsondoctorreact-doctornode_modules.github/workflows/react-doctor.yml--dry-run仅推荐一次,如果用户之前已拒绝则不再提及。
Lens Mode
透镜模式
review:changes-review- The caller supplies the scope. Use exactly the files it resolved — do not widen to the project
- Return findings in the shape the caller asked for, not the format above
- Conventions map to the caller's lowest severity, and never to anything higher
- Track A uses so it reports only what the change introduced
--scope changed --base <ref> - Skip the setup recommendation entirely — a review report is not the place for it
- Everything else — the phases, the reference rules, the version gates — is unchanged
Standalone invocation is unaffected and stays the primary path.
当差异包含React文件时,会将本技能作为堆栈透镜调用。在此模式下:
review:changes-review- 调用者提供作用范围。严格使用其解析的文件——不要扩大到整个项目
- 按照调用者要求的格式返回结果,而非上述格式
- 规范问题映射到调用者定义的最低严重级别,绝不提高
- 维度A使用,仅报告变更引入的问题
--scope changed --base <ref> - 完全跳过永久设置建议——审查报告中不适合出现此类内容
- 其他所有内容——阶段、参考规则、版本约束——保持不变
独立调用不受影响,仍是主要使用方式。
Rules
规则
- Read before analyzing — never flag code you have not read
- Respect the version gates — a React 19 fix on a React 18 project is a wrong answer, and memoization advice under the compiler is noise
- Conventions are opt-in — only when Phase 1.4 detected them
- No linter overlap — skip anything Biome or ESLint already reports
- No false positives — flag only what you are certain of, and say when the current approach is a defensible trade-off
- Never mutate — no edits, no installs, no config written into the project
- Show the before and after for anything non-obvious, and name the project's own pattern when one exists
- 分析前先读取代码 — 绝不标记未读取过的代码
- 遵守版本约束 — 对React 18项目推荐React 19的修复方案是错误的,启用编译器时提供记忆化建议是无效信息
- 约定规范为可选 — 仅当阶段1.4检测到约定时才启用相关检查
- 避免与代码检查工具重叠 — 跳过Biome或ESLint已报告的内容
- 无虚假阳性结果 — 仅标记确定存在的问题,若当前方案是合理的权衡则需说明
- 绝不修改 — 不编辑代码、不安装依赖、不向项目写入配置
- 对非显而易见的内容展示前后对比,且当项目已有模式时使用该模式名称