Skip to content

chore(rules): document render-phase ref-seed choice + no-render-in-render caveat#5333

Merged
waleedlatif1 merged 1 commit into
stagingfrom
chore-agent-react-rules
Jul 1, 2026
Merged

chore(rules): document render-phase ref-seed choice + no-render-in-render caveat#5333
waleedlatif1 merged 1 commit into
stagingfrom
chore-agent-react-rules

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Documents two recurring React pitfalls surfaced during the /w react-doctor cleanup, so future coding agents avoid them.
  • sim-hooks.md: the prevX render-phase idiom now explains that the ref seed decides mount behavior — seed a sentinel (useRef(null)) when the replaced effect did real work on mount, else the mount action is silently dropped (this was a real bug we caught). Also clarifies useStateuseRef is safe only when the value is never read in render and never a hook dependency.
  • sim-components.md: adds no-render-in-render to the known react-doctor false positives — a helper called inline is reconciled by position and does not remount, so extracting it is usually churn/risk unless mechanical.

Type of Change

  • Chore / docs (agent rule files only)

Testing

Docs-only. Cross-checked against existing rules for contradictions — deliberately did not add notes already covered (e.g. toSorted runtime-polyfill, no-barrel-import, rerender-state-only-in-handlers, absolute-import rules), and dropped a proposed toSorted/lib note that would have been wrong now that apps/sim/tsconfig.json sets lib: ES2023.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jul 1, 2026 8:40pm

Request Review

@cursor

cursor Bot commented Jul 1, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Documentation-only updates to Claude/agent rule files; no runtime, auth, or data-path changes.

Overview
Extends agent rule docs in .claude/rules/ so react-doctor / cleanup passes don’t repeat known pitfalls—no application code changes.

sim-hooks.md adds guidance after the prevX render-phase reset pattern: the initial useRef value controls first-mount behavior (use a sentinel when mount-time work must run; always update the ref unconditionally; place the block before early returns). It also tightens when useStateuseRef is safe—only when the value isn’t read in render/JSX and isn’t a hook dependency, with a cross-reference to rerender-state-only-in-handlers.

sim-components.md lists no-render-in-render as a react-doctor false positive: inline helpers like {renderRow()} don’t remount by position, so extracting them is usually churn and can hurt focus/scroll unless the refactor is mechanical.

Reviewed by Cursor Bugbot for commit 5da3dab. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Documentation-only update to two agent rule files under .claude/rules/, recording a pair of React pitfalls uncovered during a react-doctor cleanup pass so future coding agents avoid repeating them.

  • sim-hooks.md: The prevX idiom now explicitly documents the ref-seed/sentinel choice — seeding the current prop value suppresses the mount action (correct when the initial state is already set), while useRef(null) forces it to fire; also clarifies that useState→useRef is only safe when the value is never read in render and never appears in a hook dep array.
  • sim-components.md: Adds no-render-in-render to the known react-doctor false-positive list, explaining that a helper called inline is reconciled by position and does not remount, so extracting it is usually churn unless the helper is genuinely a component defined during render.

Confidence Score: 5/5

Documentation-only additions to agent rule files; no executable code is changed and no runtime behavior is affected.

Both additions are technically accurate, consistent with the existing code examples in the files, and address real patterns (silent mount-action drop, incorrect useState→useRef conversion, no-render-in-render false positive) without contradicting any other rules in the codebase.

No files require special attention.

Important Files Changed

Filename Overview
.claude/rules/sim-hooks.md Adds two new paragraphs: one documenting the ref-seed/sentinel choice for the prevX render-phase idiom (including the silent-drop bug), and one clarifying when useState→useRef conversion is safe. Content is technically accurate and consistent with the existing code example.
.claude/rules/sim-components.md Inserts a no-render-in-render entry into the react-doctor false-positive list. The distinction between called-inline helpers (reconciled by position, no remount) vs. components defined during render (new type identity, causes remount) is technically correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["prevX ref idiom needed"] --> B{"Does effect do real work\non mount?"}
    B -- "No (e.g. modal mounts closed)" --> C["useRef(currentPropValue)\nGuard = false on mount\nMount action skipped ✓"]
    B -- "Yes (panel already active,\nprop already matches)" --> D["useRef(null) — sentinel\nGuard = true on mount\nMount action fires ✓"]
    C --> E["Update ref unconditionally\ninside the block"]
    D --> E
    E --> F{"Value ever read in\nrender or dep array?"}
    F -- "Yes" --> G["Keep as useState\n(ref mutation won't re-render)"]
    F -- "No (handler / effect body only)" --> H["Safe to convert to useRef"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["prevX ref idiom needed"] --> B{"Does effect do real work\non mount?"}
    B -- "No (e.g. modal mounts closed)" --> C["useRef(currentPropValue)\nGuard = false on mount\nMount action skipped ✓"]
    B -- "Yes (panel already active,\nprop already matches)" --> D["useRef(null) — sentinel\nGuard = true on mount\nMount action fires ✓"]
    C --> E["Update ref unconditionally\ninside the block"]
    D --> E
    E --> F{"Value ever read in\nrender or dep array?"}
    F -- "Yes" --> G["Keep as useState\n(ref mutation won't re-render)"]
    F -- "No (handler / effect body only)" --> H["Safe to convert to useRef"]
Loading

Reviews (1): Last reviewed commit: "chore(rules): document render-phase ref-..." | Re-trigger Greptile

… + no-render-in-render caveat

Two recurring pitfalls surfaced by the /w react-doctor pass, verified against
react.dev:
- sim-hooks.md: adjusting state on a prop transition uses the React-canonical
  useState prev-value tracker (NOT a useRef — React forbids reading/writing
  ref.current during render; the react-hooks 'refs' lint flags it, and useState
  is concurrent-safe). The tracker's initial value decides mount behavior
  (sentinel vs current value) — a mis-seed silently drops the mount action. The
  existing useRef variant is noted as discouraged for new code.
- sim-components.md: no-render-in-render is a false positive for a helper called
  inline (reconciled by position, no remount); extract only when mechanical.

Refs: react.dev useState 'Storing information from previous renders'; useRef
'Do not write or read ref.current during rendering'; react-hooks 'refs' lint.
@waleedlatif1 waleedlatif1 force-pushed the chore-agent-react-rules branch from 5da3dab to 781fbea Compare July 1, 2026 20:36
@waleedlatif1 waleedlatif1 merged commit 2c5ee4a into staging Jul 1, 2026
15 checks passed
@waleedlatif1 waleedlatif1 deleted the chore-agent-react-rules branch July 1, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant