Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .claude/agents/code-inline-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,110 @@ function ReportScreen({ params: { reportID }}) {

---

### [CLEAN-REACT-PATTERNS-2] Let components own their behavior and effects

- **Search patterns**: Large prop counts in JSX, props named `*Report`, `*Policy`, `*Transaction`, `*Actions`, `useOnyx`/context results passed directly as props

- **Condition**: Flag when a parent component acts as a pure data intermediary — fetching or computing state only to pass it to children without using it for its own logic.

**Signs of violation:**
- Parent imports hooks/contexts only to satisfy child's data needs
- Props that are direct pass-throughs of hook results (e.g., `report={reportOnyx}`)
- Component receives props that are just passed through to children or that it could fetch itself
- Removing or commenting out the child would leave unused variables in the parent
Comment thread
adhorodyski marked this conversation as resolved.

**DO NOT flag if:**
- Props are minimal, domain-relevant identifiers (e.g., `reportID`, `transactionID`, `policyID`)
- Props are callback/event handlers for coordination (e.g., `onSelectRow`, `onLayout`, `onPress`)
- Props are structural/presentational that can't be derived internally (e.g., `style`, `testID`)
- Parent genuinely uses the data for its own rendering or logic
- Data is shared coordination state that parent legitimately owns (e.g., selection state managed by parent)

- **Reasoning**: When parent components compute and pass behavioral state to children, if a child's requirements change, then parent components must change as well, increasing coupling and causing behavior to leak across concerns. Letting components own their behavior keeps logic local, allows independent evolution, and follows the principle: "If removing a child breaks parent behavior, coupling exists."

Good (component owns its behavior):

- Component receives only IDs and handlers
- Internally accesses stores, contexts, and computes values
- Children follow the same pattern

```tsx
<OptionRowLHNData
reportID={reportID}
onSelectRow={onSelectRow}
/>
```

```tsx
function OptionRowLHNData({reportID, onSelectRow}) {
// Component fetches its own data
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`);
const [viewMode] = useOnyx(ONYXKEYS.NVP_VIEW_MODE);
// ... other data this component needs

return (
<View>
{/* Children own their state too */}
<Avatars reportID={reportID} />
<DisplayNames reportID={reportID} />
<Status reportID={reportID} />
</View>
);
}
```

Bad (parent micromanages child's state):

- Parent gathers, computes, and dictates the child's entire contextual awareness
- Parent imports hooks/stores only because the child needs the information
- Double coupling: parent → child's dependencies, child → prop names/types

```tsx
<OptionRowLHNData
reportID={reportID}
fullReport={item}
reportAttributes={itemReportAttributes}
oneTransactionThreadReport={itemOneTransactionThreadReport}
reportNameValuePairs={itemReportNameValuePairs}
reportActions={itemReportActions}
parentReportAction={itemParentReportAction}
iouReportReportActions={itemIouReportReportActions}
policy={itemPolicy}
invoiceReceiverPolicy={itemInvoiceReceiverPolicy}
personalDetails={personalDetails ?? {}}
transaction={itemTransaction}
lastReportActionTransaction={lastReportActionTransaction}
receiptTransactions={transactions}
viewMode={optionMode}
isOptionFocused={!shouldDisableFocusOptions}
lastMessageTextFromReport={lastMessageTextFromReport}
onSelectRow={onSelectRow}
preferredLocale={preferredLocale}
hasDraftComment={hasDraftComment}
transactionViolations={transactionViolations}
onLayout={onLayoutItem}
shouldShowRBRorGBRTooltip={shouldShowRBRorGBRTooltip}
activePolicyID={activePolicyID}
onboardingPurpose={introSelected?.choice}
isFullscreenVisible={isFullscreenVisible}
isReportsSplitNavigatorLast={isReportsSplitNavigatorLast}
isScreenFocused={isScreenFocused}
localeCompare={localeCompare}
testID={index}
isReportArchived={isReportArchived}
lastAction={lastAction}
lastActionReport={lastActionReport}
/>
```

In this example:
- The parent fetches `fullReport`, `policy`, `transaction`, `reportActions`, `personalDetails`, `transactionViolations`, and routing/layout state
- These dependencies exist only because the child needs them — the parent is a data intermediary
- If `OptionRowLHNData` requirements change, the parent must change too

---

## Instructions

1. **First, get the list of changed files and their diffs:**
Expand Down
Loading