[No QA] ai-reviewer: rules for React's escape hatches#81651
[No QA] ai-reviewer: rules for React's escape hatches#81651adhorodyski wants to merge 1 commit intoExpensify:mainfrom
Conversation
- Suggest useSyncExternalStore for external subscriptions - Warn on async useEffect race conditions without cleanup - Detect unguarded non-idempotent initialization in useEffect with []
|
@ShridharGoel Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #74367 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
|
|
||
| ### [PERF-14] Use `useSyncExternalStore` for external store subscriptions | ||
|
|
||
| - **Search patterns**: `addEventListener`, `subscribe`, `useEffect`, `useState` |
There was a problem hiding this comment.
This seems quite vague, could we narrow this down at all?
There was a problem hiding this comment.
Tried that, but decided to focus on good conditions so it filters out false positives based on more a more nuanced description. I'd leave it as is and improve on as we go if it proves to be too little.
|
|
||
| - **Condition**: Flag ONLY when ALL of these are true: | ||
|
|
||
| - A `useEffect` subscribes to an external source (DOM events, third-party store, browser API) |
|
|
||
| ### [PERF-16] Guard initialization logic against double-execution | ||
|
|
||
| - **Search patterns**: `useEffect(`, `}, [])`, `loadData`, `init`, `checkAuth`, `configure`, `setup`, `register`, `start` |
There was a problem hiding this comment.
Also seems a bit open for false positives. Not sure how this could be improved though
Julesssss
left a comment
There was a problem hiding this comment.
Looking good, it would be great to tighten up some of the search patterns though if possible.
Also could you create a draft PR we can test this workflow against to see if the issues are caught?
| }, [query]); | ||
| ``` | ||
|
|
||
| Good (AbortController): |
There was a problem hiding this comment.
| Good (AbortController): | |
| Better (AbortController): |
There was a problem hiding this comment.
We do all examples though as good/bad, are you sure?
There was a problem hiding this comment.
no need to change it 👍🏼
There was a problem hiding this comment.
I do think this is slightly better because it kills the request in flight rather than waiting for it to finish. but that's only tangentially related to this rule, so maybe it would only distract from the rule we're trying to enforce.
@roryabraham @kacper-mikolajczak @mountiny @tgolen
Explanation of Change
This PR adds in new AI reviewer rules as per the predesign wrapped here.
Slack thread with the original rule: https://expensify.slack.com/archives/C05LX9D6E07/p1765986623595829
useSyncExternalStorefor external store subscriptionsThe original proposal, "Only use React's escape hatches when absolutely necessary", was analyzed against our existing rule set. We found that most of its guidance is already enforced by PERF-6 through PERF-10 (derived state, key resets, event handlers, effect chains, parent communication). What remained were 3 concrete gaps: external store subscriptions, async race conditions, and init double-execution, that couldn't be covered by existing rules.
A meta-rule would have occupied context window budget without producing actionable inline comments, since "absolutely necessary" isn't a mechanically flaggable condition. Instead, these 3 rules close every remaining gap from React's You Might Not Need an Effect guide with precise flag/don't-flag criteria, giving the reviewer clear pass/fail signals rather than philosophical judgment calls.
Fixed Issues
$ #74367
PROPOSAL: https://expensify.slack.com/archives/C05LX9D6E07/p1765986623595829
Tests
Offline tests
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari