Skip to content

Commit e14bcbd

Browse files
authored
Merge branch 'Expensify:main' into allowAddingFeedForCollectCSV
2 parents cb48fad + 92ada8f commit e14bcbd

File tree

590 files changed

+13638
-13309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

590 files changed

+13638
-13309
lines changed

.claude/agents/code-inline-reviewer.md

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,31 +143,79 @@ const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
143143

144144
---
145145

146-
### [PERF-4] Memoize objects and functions passed as props
146+
### [PERF-4] Memoize objects (including arrays) and functions passed as props
147147

148-
- **Search patterns**: `useMemo`, `useCallback`, and prop passing patterns
148+
- **Search patterns**: `prop={{`, `prop={[`, `={() =>`, `prop={variable}` (where variable is non-memoized object/function)
149149

150-
- **Condition**: Objects and functions passed as props should be properly memoized or simplified to primitive values to prevent unnecessary re-renders.
151-
- **Reasoning**: React uses referential equality to determine if props changed. New object/function instances on every render trigger unnecessary re-renders of child components, even when the actual data hasn't changed. Memoization preserves referential stability.
150+
- **Applies ONLY to**: Objects (including arrays)/functions passed directly as JSX props. Does NOT apply to:
151+
- Code inside callbacks (`.then()`, event handlers)
152+
- Code inside `useEffect`/`useMemo`/`useCallback` bodies
153+
- Primitives (strings, numbers, booleans)
154+
- Already memoized values (`useMemo`/`useCallback`)
152155

153-
Good:
156+
- **Reasoning**: New object/function references break memoization of child components. Only matters when child IS memoized AND parent is NOT optimized by React Compiler.
154157

155-
```tsx
156-
const reportData = useMemo(() => ({
157-
reportID: report.reportID,
158-
type: report.type,
159-
isPinned: report.isPinned,
160-
}), [report.reportID, report.type, report.isPinned]);
158+
#### Before flagging: Run optimization check
159+
160+
**YOU MUST call `checkReactCompilerOptimization.ts` (available in PATH from `.claude/scripts/`) on EVERY .tsx file from the diff.**
161161

162-
return <ReportActionItem report={reportData} />
162+
**Call the script ONCE per file, separately. DO NOT use loops or batch processing.**
163+
164+
Example usage:
165+
```bash
166+
checkReactCompilerOptimization.ts src/components/File1.tsx
167+
checkReactCompilerOptimization.ts src/components/File2.tsx
163168
```
164169

165-
Bad:
170+
**NEVER use absolute or relative paths for this script. Call it by name only:**
171+
-`checkReactCompilerOptimization.ts src/components/Example.tsx`
172+
-`/home/runner/work/App/App/.claude/scripts/checkReactCompilerOptimization.ts ...`
173+
-`./.claude/scripts/checkReactCompilerOptimization.ts ...`
174+
175+
**"File not found"** → Assume parent is optimized and skip PERF-4.
176+
177+
#### Decision flow
178+
179+
1. **Parent in `parentOptimized`?** → YES = **Skip** (compiler auto-memoizes)
180+
181+
2. **Child has custom memo comparator that PREVENTS re-render for this prop?**
182+
→ Use `sourcePath` from script output to read child's source file
183+
→ Grep for `React.memo` or `memo(`
184+
→ If custom comparator prevents re-render despite new reference for this prop → **Skip**
166185

186+
3. **Child is memoized?** (`optimized: true` OR `React.memo`)
187+
- NO → **Skip** (child re-renders anyway)
188+
- YES → **Flag PERF-4**
189+
190+
#### Examples
191+
192+
**Flag** (parent NOT optimized, child IS memoized, no custom comparator):
193+
```tsx
194+
// Script output: parentOptimized: [], child MemoizedList optimized: true
195+
// No custom comparator found
196+
return <MemoizedList options={{ showHeader: true }} />;
197+
```
198+
199+
**Skip - custom comparator** (comparator prevents re-render for this prop):
167200
```tsx
168-
const [report] = useOnyx(`ONYXKEYS.COLLECTION.REPORT${iouReport.id}`);
201+
// Script output: sourcePath: "src/components/PopoverMenu.tsx"
202+
// PopoverMenu.tsx has custom memo comparator that handles anchorPosition
203+
return <PopoverMenu anchorPosition={{x: 0, y: 0}} />;
204+
```
169205

170-
return <ReportActionItem report={report} />
206+
**Skip - parent optimized**:
207+
```tsx
208+
// Script output: parentOptimized: ["MyComponent"]
209+
// React Compiler auto-memoizes - no manual memoization needed
210+
return <MemoizedList options={{ showHeader: true }} />;
211+
```
212+
213+
**Skip - spread props with stable inner values**:
214+
```tsx
215+
// Spread is OK when inner values come from memoized sources
216+
// illustration from useMemoizedLazyIllustrations, illustrationStyle from useThemeStyles
217+
const illustration = useAboutSectionIllustration();
218+
return <Section {...illustration} />;
171219
```
172220

173221
---

.claude/commands/review-code-pr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
allowed-tools: Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(addPrReaction.sh:*),Bash(createInlineComment.sh:*)
2+
allowed-tools: Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(addPrReaction.sh:*),Bash(createInlineComment.sh:*),Bash(checkReactCompilerOptimization.ts:*)
33
description: Review a code contribution pull request
44
---
55

0 commit comments

Comments
 (0)