react-doctor/rn-list-callback-per-row
Hoist the handler with useCallback at list scope and pass the row id as a primitive prop, so the row's memo() shallow-compare actually hits
- Category: React Native
- Severity: warn
- Source:
oxlint-plugin-react-doctor - Framework: react-native
- Enabled when: framework=react-native and capabilities=react-native
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Verify an onPress, onLongPress, onPressIn, onPressOut, onSelect, or onClick JSX attribute inside renderItem is an inline arrow or function expression — that's a new closure for every row on every render. Lower-impact false positive when the row component isn't wrapped in React.memo (no shallow compare to break).
Fix prompt
Use this once validation confirms the diagnostic is real.
Hoist the handler at list scope (const onPressRow = useCallback((id) => ..., [])), pass id={item.id} into the memo-wrapped row component, and call onPress={() => onPressRow(id)} inside the row (or use a tiny wrapper component). The row's shallow compare then hits and avoids re-render. See https://react.dev/reference/react/useCallback
Related rules
More React Native rules from the rules reference:
react-doctor/rn-list-data-mapped: Wrap the projection in `useMemo(() => items.map(...), [items])` so the list's `data` prop has a stable reference across parent rendersreact-doctor/rn-list-missing-estimated-item-size: Add estimatedItemSize so FlashList/LegendList sizes its initial container pool correctly: <FlashList data={items} estimatedItemSize={64} />react-doctor/rn-list-recyclable-without-types: Add `getItemType={item => item.kind}` so FlashList keeps separate recycle pools per item type — heterogeneous rows shouldn't share recycled cellsreact-doctor/rn-no-deep-imports: Import from the "react-native" package root, not the deprecated "react-native/Libraries/..." subpath: import { Alert } from "react-native"react-doctor/rn-no-deprecated-modules: Import from the community package instead — deprecated modules were removed from the react-native core