references/fix-reference.md
# Fix Reference
Match profiler findings and semantic sweep results to concrete fixes. With React Compiler active, skip the first three rows for the components it compiles; keep them for components it skips (`compilationMode: "annotation"`, `"use no memo"`, a `sources` filter).
| Finding | Fix | Detail |
| -------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Re-renders with same props | `React.memo(Comp)` | Only where the props really are equal between renders |
| Expensive recomputation / unstable callbacks | `useMemo(fn, [deps])` / `useCallback(fn, [deps])` | `useCallback` must pair with `React.memo` on child; alone it has no effect |
| Inline objects/arrays in JSX | `StyleSheet.create()` / module-level const | New reference every render breaks shallow equality |
| List jank | `removeClippedSubviews`, `maxToRenderPerBatch`, `windowSize`, `getItemLayout` | Or migrate to `@shopify/flash-list` (v2 needs the New Architecture) |
| JS-thread animation jank | `useNativeDriver: true` or `react-native-reanimated` | `useNativeDriver` can't animate layout props (width, height, margins, …) |
| Heavy work during transitions | `requestIdleCallback()` | Runs the work when the JS thread is idle; `InteractionManager` is deprecated |
| Slow startup | Defer heavy imports (lazy `require()`) | Check inline requires in the Metro config (on in bare RN, off in Expo) |
| Redundant, heavy, or n+1 network calls | `view-network-logs` → `view-network-request-details` | Batch, debounce, or cache at the data layer |
references/lint-rules.md
# Phase 1: Lint Rules
Run once at the project root. Catches mechanical issues deterministically.
Install missing plugins before running. On ESLint 10, `eslint-plugin-react-native` crashes: install with `--legacy-peer-deps` (npm; pnpm only warns) and run `npx eslint@9`.
With React Compiler active, leave out the react-perf rules, `react/jsx-no-bind` and `react-native/no-inline-styles`, unless the compiler skips some components (`compilationMode: "annotation"`, `"use no memo"`, a `sources` filter).
## Rules
### Performance (eslint-plugin-react-perf)
| Rule | Catches |
| ---------------------------------------- | -------------------------------------------------------- |
| `react-perf/jsx-no-new-object-as-prop` | Object literals `{}` as JSX props - new ref every render |
| `react-perf/jsx-no-new-array-as-prop` | Array literals `[]` as JSX props - new ref every render |
| `react-perf/jsx-no-new-function-as-prop` | Arrow functions / function expressions as JSX props |
| `react-perf/jsx-no-jsx-as-prop` | JSX elements as prop values (e.g. `icon={<Icon />}`) |
### React (eslint-plugin-react)
| Rule | Catches |
| ----------------------------------------- | ------------------------------------------------------------------- |
| `react/no-array-index-key` | `key={index}` - incorrect reconciliation on reorder |
| `react/jsx-no-bind` | `.bind()` in JSX props - new function ref every render |
| `react/jsx-no-constructed-context-values` | Object/array literals as Context `value` - re-renders all consumers |
| `react/no-unstable-nested-components` | Components defined inside render - full remount each render |
| `react/no-object-type-as-default-prop` | Object/array defaults in destructuring (e.g. `{ items = [] }`) |
### React Native (eslint-plugin-react-native)
| Rule | Catches |
| --------------------------------------------- | ------------------------------------------------ |
| `react-native/no-inline-styles` | Inline `style={{}}` - defeats shallow comparison |
| `react-native/no-unused-styles` | StyleSheet rules never referenced |
| `react-native/no-color-literals` | Color literals in styles instead of constants |
| `react-native/no-single-element-style-arrays` | `style={[single]}` instead of `style={single}` |
### Hooks (eslint-plugin-react-hooks)
| Rule | Catches |
| ----------------------------- | ---------------------------------------- |
| `react-hooks/exhaustive-deps` | Missing/incorrect hook dependency arrays |
| `react-hooks/rules-of-hooks` | Hooks called conditionally or in loops |
### Error handling (ESLint core)
| Rule | Catches |
| ------------------------------------------ | ------------------------------------- |
| `no-empty` (with `allowEmptyCatch: false`) | Empty catch blocks - swallowed errors |
## Procedure
1. Add the rules above for this run only: extend the project's ESLint config, or on ESLint 10 use a temporary flat config that spreads it. With no project config, create a temporary `eslint.config.mjs`; on a TypeScript project give it `typescript-eslint`'s parser, or every `.tsx` file fails to parse.
2. Run: `npx eslint --format json <src_dir>` (`npx eslint@9 -c <temp config>` on ESLint 10); replace `<src_dir>` with the project's JS/TS source root (check `package.json` scripts or look for `src/`, `app/`, `lib/`)
3. Parse output into: `file:line -> rule -> message`.
references/semantic-checklist.md
# Phase 2: Semantic Sweep
Work through each area. Do not skip.
See [fix-reference.md](fix-reference.md) for concrete fix patterns per finding.
## Checklist
### Memoization
Check every exported function component: is it rendered in a list, a frequently-updating parent, or a context consumer? If yes and props are stable, wrap in `React.memo`. Check context providers for unstable `value` props. If React Compiler is active, check only the components it skips (`compilationMode: "annotation"`, `"use no memo"`, a `sources` filter).
### List rendering
Check all list-like rendering: ScrollView+map, manually iterated arrays, deeply nested FlatLists. Verify lists use virtualization (`FlatList`/`FlashList`), stable keys, and proper item sizing.
### Animations
Check all animation code against current library best practices. Prefer Reanimated over the Animated API. Check for JS-thread animation bottlenecks (`requestAnimationFrame` loops, state-driven animations).
### Async patterns
Check for sequential `await` calls that could be `Promise.all`. Check for missing `AbortController` / cancellation on unmount. Check for fetch waterfalls (parent fetches → child fetches → grandchild fetches).
### Effect cleanup
Check all `useEffect` hooks that create timers, listeners, or subscriptions. Verify each returns a cleanup function. Check for effects missing dependency arrays (runs every render).
### State hygiene
Check for unused state (set but never rendered), unbounded state growth (arrays/objects that grow without cap), and derived state that should be computed during render instead.
### Monolithic context
Flag but do NOT auto-fix. Report as architectural recommendation.
SKILL.md
---
name: argent-react-native-optimization
description: Optimizes a React Native app by profiling first to find real bottlenecks, then sweeping for mechanical issues. Entry-point for all performance work. Use when the app feels slow, user asks to optimize, fix re-renders, reduce jank, or improve startup. Delegates to argent-react-native-profiler for measurement.
---
## Rules
- Do not apply shotgun optimizations. Measure first, define what "good enough" looks like (target metric + threshold), fix the top offender, re-measure honestly.
- **Profile for discovery, not only verification.** Use the profiler to find issues static analysis missed, not only to confirm fixes.
- **Verify before fixing:** recollect the evidence and conclude whether the fix is worth undertaking. Validate a fix with `debugger-evaluate` before committing it.
- **One fix per cycle for architectural changes.** Mechanical batch fixes (inline styles, index keys) can be grouped; re-profile once after the batch. When the measurement involves device interaction, record it as an e2e test (`argent-create-e2e` skill) before the first run so every cycle replays identical steps.
- **React Compiler**: if the project uses it (`babel-plugin-react-compiler` in the Babel config, or `experiments.reactCompiler: true` in the Expo config), skip memoization fixes (`React.memo`, `useMemo`, `useCallback`, hoisting inline objects and functions) in every phase; the compiler does them. Keep them for components the compiler skips (`compilationMode: "annotation"`, `"use no memo"`, a `sources` filter). Where the profiler report marks a component ⚠️ (bailout suspected), fix what stops the compiler.
- **Sub-agents**: Phases 1–2 dispatch sub-agents: one per file for lint results, one per checklist item for semantic. Sub-agents CANNOT touch the device - all profiling and E2E verification must happen in the main agent.
## Pipeline
**Lint and semantic sweeps catch deterministic issues cheaply. Profiling finds runtime bottlenecks that static analysis misses. Do both.**
Copy this checklist into your TODO list:
```
Optimization Progress:
- [ ] Phase 1: Lint sweep (deterministic: catch mechanical issues without a running app)
- [ ] Phase 2: Semantic sweep (judgment: memoization, lists, animations, etc.)
- [ ] Phase 3: Baseline profile (find real bottlenecks, fix top offenders)
- [ ] Phase 4: Verify no regressions (crashes, errors, red screens)
- [ ] Re-run lint to confirm the fixes added no new issues and none were missed
```
### Phase 1: Lint sweep
Run ESLint once at the project root with a comprehensive RN performance ruleset. Dispatch sub-agents to fix results: one per file, in parallel.
See [references/lint-rules.md](references/lint-rules.md) for ruleset and procedure.
### Phase 2: Semantic sweep
Review each area requiring judgment: memoization, list rendering, animations, async patterns, effect cleanup, state hygiene, context architecture. Dispatch one sub-agent per checklist item.
See [references/semantic-checklist.md](references/semantic-checklist.md) for full checklist.
### Phase 3: Profiling
1. For a quick look without a session, `react-profiler-renders` lists how many instances of each component are mounted (not how often they re-render).
2. Load the `argent-react-native-profiler` skill and follow its workflow (React and native profiling together) on the key user flows: the screens the user named, or all major flows. It covers analysis, drill-down, and re-profiling after each fix.
3. Cross-reference the profiling results with the Phase 1–2 findings, and fix the highest-impact issues top-down. Re-profile after architectural changes; batch mechanical fixes.
### Phase 4: Verify no regressions
Navigate every screen and UI flow within scope (the entire app if no scope was given, via `argent-device-interact`) and confirm each renders without errors. Check `debugger-log-registry` for warnings and errors (`Grep` its log file). Argent hides LogBox toasts once a `debugger-*` tool connects, so screenshots catch only full-screen red errors. Look for regressions the fixes introduced (e.g. fewer re-renders but higher CPU, or new jank on a different screen). Main agent only.