# WhyRN > WhyRN (npm package `whyrn.dev`) finds the re-renders worth fixing in React Native apps - components that rendered although nothing they depend on really changed, and whose wasted renders cost real time (≥ 16 ms per second by default, measured with React's profiling timers) - and says what to change and where. Wrap the app in ``; Metro gets a short summary naming the component, the parent that creates the unstable prop, and the fix (`useCallback`, `useMemo`, `React.memo`, memoizing a context value). Legitimate renders and cheap avoidable ones stay quiet. Dev builds only, zero config, no native module. React 18+, React Native 0.70+, Expo Go, old and new architecture. Use WhyRN when a React Native or Expo screen is slow or janky, a FlatList stutters, or someone asks why a component re-renders. Measure before changing code, fix the cause it names, then measure again. React DevTools' "Highlight updates" shows every render; WhyRN filters to the ones you can remove and explains the fix. ## Install and use ```bash npm install -D whyrn.dev ``` ```tsx import { WhyRN } from 'whyrn.dev'; export default function App() { return ( ); } ``` Metro output (default, report="critical"): ``` ⚠️ WhyRN: 402 avoidable re-renders HeavyList ×2 · 33 ms wasted · rendered by Screen at vscode://file/Users/you/app/src/screens/Screen.tsx:148:7?whyrn 2× prop "items": new object with the same content - useMemo in Screen, then React.memo(HeavyList) Row ×400 · 200 instances · rendered by HeavyList 400× only because HeavyList re-rendered - fix HeavyList first ⚠️ WhyRN: still avoidable (same causes as above) HeavyList ×10 · 140 ms wasted · rendered by Screen at vscode://file/Users/you/app/src/screens/Screen.tsx:148:7?whyrn ``` `×N` counts renders across instances; `K instances` is the number of distinct components. `only because X re-rendered` is a consequence - fix X. `at file:line:col` is the JSX that renders the component (where the unstable prop is created); click it in the DevTools console (editor URL, `editor` prop) or tap the badge on the device to open it in the editor. Each problem is explained once; repeats are summarized every 10 s with counts and links. `report="avoidable"` shows every wasted render however cheap; `report="all"` logs every render with its real cause. ## Summary lines and fixes - `prop "x": new object with the same content - useMemo in P` - object/array/JSX literal created in P's render: `useMemo` or hoist it. - `prop "onX": new function every render - useCallback in P` - inline handler in P: `useCallback`. - `props are equal - wrap C in React.memo` - C renders only because its parent did: `React.memo(C)`. - `(they defeat React.memo(C))` - C is memoized but gets unstable props: fix the props in the parent. - `XContext got a new value with the same content - useMemo the Provider value` - provider value recreated each render. - `Store selector returned a new object with the same content` - select primitives or use a shallow selector. - `state[i] set to an equal value` - setState with a fresh but equal object: return the previous state. ## API - `` props: `enabled` (default `__DEV__`), `report` (`'critical'` default, `'avoidable'`, or `'all'`), `criticalMs` (16, wasted ms per second that make a component critical), `editor` (`'vscode'` default; `'cursor' | 'windsurf' | 'zed' | 'webstorm' | 'idea' | 'none'` or a function returning a URL), `heatmap` (persistent per-instance boxes colored by render rate over 5 s, with a ×N count), `include` / `exclude` (RegExp[] on component names), `trackHooks` (true), `logToConsole` (true), `flashDuration` (600), `flashColor`, `heatmapColdColor`, `heatmapHotColor`, `maxOverlays` (50). React Native and common library internals are always skipped. - `withWhyRN(Component, name?)` - track one component (every render), also without `` (console only). Returns the same component. - `useWhyRN(name, props)` - reasons for the current render as data. - `useRenderCount(name?)` - render count, optionally logged. ## Agent skill The npm package ships an Agent Skill at `node_modules/whyrn.dev/skills/whyrn-debug/` (works with Claude Code and Codex): ```bash mkdir -p .claude/skills .agents/skills ln -s ../../node_modules/whyrn.dev/skills/whyrn-debug .claude/skills/whyrn-debug ln -s ../../node_modules/whyrn.dev/skills/whyrn-debug .agents/skills/whyrn-debug ``` Log summarizer: `node node_modules/whyrn.dev/skills/whyrn-debug/scripts/summarize-log.mjs metro.log` ## Links - [README](https://github.com/vladbars/whyrn#readme): full documentation - [Skill](https://github.com/vladbars/whyrn/blob/main/skills/whyrn-debug/SKILL.md): agent workflow for debugging re-renders - [npm](https://www.npmjs.com/package/whyrn.dev): package - [Source](https://github.com/vladbars/whyrn): MIT